webdriver/driver.go
2023-12-10 19:09:23 +01:00

184 lines
3.5 KiB
Go

package webdriver
import (
"bufio"
"bytes"
"context"
"encoding/json"
"fmt"
"io"
"net/http"
"net/url"
"os/exec"
"strconv"
)
type Driver struct {
server *exec.Cmd
host string
port uint16
sessionID string
}
func NewDriver() (*Driver, error) {
host := "127.0.0.1"
port := uint16(4444)
ctx := context.Background()
server := exec.CommandContext(ctx, "geckodriver", "--host", host, "--port", strconv.Itoa(int(port)))
stdout, err := server.StdoutPipe()
if err != nil {
return nil, err
}
if err := server.Start(); err != nil {
return nil, err
}
scanner := bufio.NewScanner(stdout)
scanner.Scan()
return &Driver{
server: server,
host: host,
port: port,
}, nil
}
func UseDriver(host string, port uint16) *Driver {
return &Driver{
host: host,
port: port,
}
}
func (d *Driver) Close() error {
if d.server == nil {
return nil
}
if d.sessionID != "" {
if err := d.CloseSession(); err != nil {
return err
}
}
if err := d.server.Cancel(); err != nil {
return err
}
if err := d.server.Wait(); err != nil {
return err
}
return nil
}
func (d *Driver) buildSessionUrl(path string) string {
uri, err := url.JoinPath(fmt.Sprintf("http://%s:%d/session/%s", d.host, d.port, d.sessionID), path)
if err != nil {
panic(err)
}
return uri
}
func (d *Driver) buildUrl(path string) string {
uri, err := url.JoinPath(fmt.Sprintf("http://%s:%d", d.host, d.port), path)
if err != nil {
panic(err)
}
return uri
}
func (d *Driver) DoRawSessionRequest(method string, path string, body io.Reader) (*http.Response, error) {
req, err := http.NewRequest(method, d.buildSessionUrl(path), body)
if err != nil {
return nil, err
}
req.Header.Add("Content-Type", "application/json")
return http.DefaultClient.Do(req)
}
func (d *Driver) DoRawRequest(method string, path string, body io.Reader) (*http.Response, error) {
req, err := http.NewRequest(method, d.buildUrl(path), body)
if err != nil {
return nil, err
}
req.Header.Add("Content-Type", "application/json")
return http.DefaultClient.Do(req)
}
func (d *Driver) DoSessionRequest(method string, path string, body map[string]interface{}) (map[string]interface{}, error) {
if body == nil {
body = map[string]interface{}{}
}
data, err := json.Marshal(body)
if err != nil {
return nil, err
}
resp, err := d.DoRawSessionRequest(method, path, bytes.NewReader(data))
if err != nil {
return nil, err
}
defer resp.Body.Close()
respBody := map[string]interface{}{}
if err := json.NewDecoder(resp.Body).Decode(&respBody); err != nil {
return nil, err
}
return respBody, nil
}
func (d *Driver) DoRequest(method string, path string, body map[string]interface{}) (map[string]interface{}, error) {
if body == nil {
body = map[string]interface{}{}
}
data, err := json.Marshal(body)
if err != nil {
return nil, err
}
resp, err := d.DoRawRequest(method, path, bytes.NewReader(data))
if err != nil {
return nil, err
}
defer resp.Body.Close()
respBody := map[string]interface{}{}
if err := json.NewDecoder(resp.Body).Decode(&respBody); err != nil {
return nil, err
}
return respBody, nil
}
func (d *Driver) NewSession() error {
data, err := d.DoRequest(http.MethodPost, "/session", nil)
if err != nil {
return err
}
d.sessionID = data["value"].(map[string]interface{})["sessionId"].(string)
return nil
}
func (d *Driver) CloseSession() error {
_, err := d.DoSessionRequest(http.MethodDelete, "", nil)
if err != nil {
return err
}
d.sessionID = ""
return nil
}