1 package playwright
2
3 import (
4 "reflect"
5 "regexp"
6 "strings"
7 "sync"
8
9 "github.com/danwakefield/fnmatch"
10 )
11
12 type (
13 routeHandler = func(Route, Request)
14 )
15
16 func skipFieldSerialization(val reflect.Value) bool {
17 typ := val.Type()
18 return (typ.Kind() == reflect.Ptr ||
19 typ.Kind() == reflect.Interface ||
20 typ.Kind() == reflect.Map ||
21 typ.Kind() == reflect.Slice) && val.IsNil() || (val.Kind() == reflect.Interface && val.Elem().Kind() == reflect.Ptr && val.Elem().IsNil())
22 }
23
24 func transformStructValues(in interface{}) interface{} {
25 v := reflect.ValueOf(in)
26 if v.Kind() == reflect.Ptr {
27 v = v.Elem()
28 }
29 if _, ok := in.(*channel); ok {
30 return in
31 }
32 if v.Kind() == reflect.Map || v.Kind() == reflect.Struct {
33 return transformStructIntoMapIfNeeded(in)
34 }
35 if v.Kind() == reflect.Slice {
36 outSlice := []interface{}{}
37 for i := 0; i < v.Len(); i++ {
38 if !skipFieldSerialization(v.Index(i)) {
39 outSlice = append(outSlice, transformStructValues(v.Index(i).Interface()))
40 }
41 }
42 return outSlice
43 }
44 if v.Interface() == Null() || (v.Kind() == reflect.String && v.String() == Null().(string)) {
45 return "null"
46 }
47 return in
48 }
49
50 func transformStructIntoMapIfNeeded(inStruct interface{}) map[string]interface{} {
51 out := make(map[string]interface{})
52 v := reflect.ValueOf(inStruct)
53 if v.Kind() == reflect.Ptr {
54 v = v.Elem()
55 }
56 typ := v.Type()
57 if v.Kind() == reflect.Struct {
58
59 for i := 0; i < v.NumField(); i++ {
60 fi := typ.Field(i)
61
62 if !skipFieldSerialization(v.Field(i)) {
63
64
65 tagv := fi.Tag.Get("json")
66 key := strings.Split(tagv, ",")[0]
67 if key == "" {
68 key = fi.Name
69 }
70 out[key] = transformStructValues(v.Field(i).Interface())
71 }
72 }
73 } else if v.Kind() == reflect.Map {
74
75 for _, key := range v.MapKeys() {
76 if !skipFieldSerialization(v.MapIndex(key)) {
77 out[key.String()] = transformStructValues(v.MapIndex(key).Interface())
78 }
79 }
80 }
81 return out
82 }
83
84
85 func transformOptions(options ...interface{}) map[string]interface{} {
86 var base map[string]interface{}
87 var option interface{}
88
89 if len(options) == 0 {
90 return make(map[string]interface{})
91 }
92 if len(options) == 1 {
93
94 base = make(map[string]interface{})
95 option = options[0]
96 } else if len(options) == 2 {
97
98
99
100 base = transformStructIntoMapIfNeeded(options[0])
101 option = options[1]
102 }
103 v := reflect.ValueOf(option)
104 if v.Kind() == reflect.Slice {
105 if v.Len() == 0 {
106 return base
107 }
108 option = v.Index(0).Interface()
109 }
110
111 if option == nil {
112 return base
113 }
114 v = reflect.ValueOf(option)
115
116 if v.Kind() == reflect.Ptr {
117 v = v.Elem()
118 }
119
120 optionMap := transformStructIntoMapIfNeeded(v.Interface())
121 for key, value := range optionMap {
122 base[key] = value
123 }
124 return base
125 }
126
127 func remapValue(inMapValue reflect.Value, outStructValue reflect.Value) {
128 switch outStructValue.Type().Kind() {
129 case reflect.Bool:
130 outStructValue.SetBool(inMapValue.Bool())
131 case reflect.String:
132 outStructValue.SetString(inMapValue.String())
133 case reflect.Float64:
134 outStructValue.SetFloat(inMapValue.Float())
135 case reflect.Int:
136 outStructValue.SetInt(int64(inMapValue.Float()))
137 case reflect.Slice:
138 outStructValue.Set(reflect.MakeSlice(outStructValue.Type(), inMapValue.Len(), inMapValue.Cap()))
139 for i := 0; i < inMapValue.Len(); i++ {
140 remapValue(inMapValue.Index(i).Elem(), outStructValue.Index(i))
141 }
142 case reflect.Struct:
143 structTyp := outStructValue.Type()
144 for i := 0; i < outStructValue.NumField(); i++ {
145 fi := structTyp.Field(i)
146 key := strings.Split(fi.Tag.Get("json"), ",")[0]
147 structField := outStructValue.Field(i)
148 structFieldDeref := outStructValue.Field(i)
149 if structField.Type().Kind() == reflect.Ptr {
150 structField.Set(reflect.New(structField.Type().Elem()))
151 structFieldDeref = structField.Elem()
152 }
153 for _, e := range inMapValue.MapKeys() {
154 if key == e.String() {
155 value := inMapValue.MapIndex(e)
156 remapValue(value.Elem(), structFieldDeref)
157 }
158 }
159 }
160 default:
161 panic(inMapValue.Interface())
162 }
163 }
164
165 func remapMapToStruct(inputMap interface{}, outStruct interface{}) {
166 remapValue(reflect.ValueOf(inputMap), reflect.ValueOf(outStruct).Elem())
167 }
168
169 func isFunctionBody(expression string) bool {
170 expression = strings.TrimSpace(expression)
171 return strings.HasPrefix(expression, "function") ||
172 strings.HasPrefix(expression, "async ") ||
173 strings.Contains(expression, "=> ")
174 }
175
176 type urlMatcher struct {
177 urlOrPredicate interface{}
178 }
179
180 func newURLMatcher(urlOrPredicate interface{}) *urlMatcher {
181 return &urlMatcher{
182 urlOrPredicate: urlOrPredicate,
183 }
184 }
185
186 func (u *urlMatcher) Matches(url string) bool {
187 switch v := u.urlOrPredicate.(type) {
188 case *regexp.Regexp:
189 return v.MatchString(url)
190 case string:
191 return fnmatch.Match(v, url, 0)
192 }
193 if reflect.TypeOf(u.urlOrPredicate).Kind() == reflect.Func {
194 function := reflect.ValueOf(u.urlOrPredicate)
195 result := function.Call([]reflect.Value{reflect.ValueOf(url)})
196 return result[0].Bool()
197 }
198 panic(u.urlOrPredicate)
199 }
200
201 type routeHandlerEntry struct {
202 matcher *urlMatcher
203 handler routeHandler
204 }
205
206 func newRouteHandlerEntry(matcher *urlMatcher, handler routeHandler) *routeHandlerEntry {
207 return &routeHandlerEntry{
208 matcher: matcher,
209 handler: handler,
210 }
211 }
212
213 type safeStringSet struct {
214 sync.Mutex
215 v []string
216 }
217
218 func (s *safeStringSet) Has(expected string) bool {
219 s.Lock()
220 defer s.Unlock()
221 for _, v := range s.v {
222 if v == expected {
223 return true
224 }
225 }
226 return false
227 }
228
229 func (s *safeStringSet) Add(v string) {
230 if s.Has(v) {
231 return
232 }
233 s.Lock()
234 s.v = append(s.v, v)
235 s.Unlock()
236 }
237
238 func (s *safeStringSet) Remove(remove string) {
239 s.Lock()
240 defer s.Unlock()
241 newSlice := make([]string, 0)
242 for _, v := range s.v {
243 if v != remove {
244 newSlice = append(newSlice, v)
245 }
246 }
247 if len(s.v) != len(newSlice) {
248 s.v = newSlice
249 }
250 }
251
252 func newSafeStringSet(v []string) *safeStringSet {
253 return &safeStringSet{
254 v: v,
255 }
256 }
257
258 const defaultTimeout = 30 * 1000
259
260 type timeoutSettings struct {
261 parent *timeoutSettings
262 timeout float64
263 navigationTimeout float64
264 }
265
266 func (t *timeoutSettings) SetTimeout(timeout float64) {
267 t.timeout = timeout
268 }
269
270 func (t *timeoutSettings) Timeout() float64 {
271 if t.timeout != 0 {
272 return t.timeout
273 }
274 if t.parent != nil {
275 return t.parent.Timeout()
276 }
277 return defaultTimeout
278 }
279
280 func (t *timeoutSettings) SetNavigationTimeout(navigationTimeout float64) {
281 t.navigationTimeout = navigationTimeout
282 }
283
284 func (t *timeoutSettings) NavigationTimeout() float64 {
285 if t.navigationTimeout != 0 {
286 return t.navigationTimeout
287 }
288 if t.parent != nil {
289 return t.parent.NavigationTimeout()
290 }
291 return defaultTimeout
292 }
293
294 func newTimeoutSettings(parent *timeoutSettings) *timeoutSettings {
295 return &timeoutSettings{
296 parent: parent,
297 timeout: defaultTimeout,
298 navigationTimeout: defaultTimeout,
299 }
300 }
301
302 func waitForEvent(emitter EventEmitter, event string, predicate ...interface{}) <-chan interface{} {
303 evChan := make(chan interface{}, 1)
304 removeHandler := make(chan bool, 1)
305 handler := func(ev ...interface{}) {
306 if len(predicate) == 0 {
307 if len(ev) == 1 {
308 evChan <- ev[0]
309 } else {
310 evChan <- nil
311 }
312 removeHandler <- true
313 } else if len(predicate) == 1 {
314 result := reflect.ValueOf(predicate[0]).Call([]reflect.Value{reflect.ValueOf(ev[0])})
315 if result[0].Bool() {
316 evChan <- ev[0]
317 removeHandler <- true
318 }
319 }
320 }
321 go func() {
322 <-removeHandler
323 emitter.RemoveListener(event, handler)
324 }()
325 emitter.On(event, handler)
326 return evChan
327 }
328
329
330 type SelectOptionValues struct {
331 Values *[]string
332 Indexes *[]int
333 Labels *[]string
334 Elements *[]ElementHandle
335 }
336
337 func convertSelectOptionSet(values SelectOptionValues) map[string]interface{} {
338 out := make(map[string]interface{})
339 if values == (SelectOptionValues{}) {
340 return out
341 }
342
343 var o []map[string]interface{}
344 if values.Values != nil {
345 for _, v := range *values.Values {
346 m := map[string]interface{}{"value": v}
347 o = append(o, m)
348 }
349 }
350 if values.Indexes != nil {
351 for _, i := range *values.Indexes {
352 m := map[string]interface{}{"index": i}
353 o = append(o, m)
354 }
355 }
356 if values.Labels != nil {
357 for _, l := range *values.Labels {
358 m := map[string]interface{}{"label": l}
359 o = append(o, m)
360 }
361 }
362 if o != nil {
363 out["options"] = o
364 }
365
366 var e []*channel
367 if values.Elements != nil {
368 for _, eh := range *values.Elements {
369 e = append(e, eh.(*elementHandleImpl).channel)
370 }
371 }
372 if e != nil {
373 out["elements"] = e
374 }
375
376 return out
377 }
378
379 func unroute(channel *channel, inRoutes []*routeHandlerEntry, url interface{}, handlers ...routeHandler) ([]*routeHandlerEntry, error) {
380 var handler routeHandler
381 if len(handlers) == 1 {
382 handler = handlers[0]
383 }
384 handlerPtr := reflect.ValueOf(handler).Pointer()
385
386 routes := make([]*routeHandlerEntry, 0)
387
388 for _, route := range inRoutes {
389 routeHandlerPtr := reflect.ValueOf(route.handler).Pointer()
390 if route.matcher.urlOrPredicate != url ||
391 (handler != nil && routeHandlerPtr != handlerPtr) {
392 routes = append(routes, route)
393 }
394 }
395
396 if len(routes) == 0 {
397 _, err := channel.Send("setNetworkInterceptionEnabled", map[string]interface{}{
398 "enabled": false,
399 })
400 if err != nil {
401 return nil, err
402 }
403 }
404 return routes, nil
405 }
406
407 func serializeMapToNameAndValue(headers map[string]string) []map[string]string {
408 serialized := make([]map[string]string, 0)
409 for name, value := range headers {
410 serialized = append(serialized, map[string]string{
411 "name": name,
412 "value": value,
413 })
414 }
415 return serialized
416 }
417
View as plain text