Skip to content

Commit

Permalink
result
Browse files Browse the repository at this point in the history
  • Loading branch information
herudi committed Dec 14, 2024
1 parent 5221c4f commit 9e6efbe
Show file tree
Hide file tree
Showing 6 changed files with 124 additions and 85 deletions.
13 changes: 5 additions & 8 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,19 +1,16 @@
# CDV

Drive chrome-devtools in `V` programming language and runs in the headless by default.
Chrome Devtools Protocol for `V` and runs in the headless by default.

> This is Low-Level API from spec https://chromedevtools.github.io/devtools-protocol.
> This project based on spec https://chromedevtools.github.io/devtools-protocol.
> Experimental.
## Clone
## Install
```bash
cd your_project
git clone https://github.com/herudi/cdv
v install herudi.cdv
```
## Example
```v
import cdv
import herudi.cdv
fn inspect_network(mut browser cdv.Browser) ! {
mut tab := browser.new_tab()!
Expand Down
77 changes: 26 additions & 51 deletions browser.v
Original file line number Diff line number Diff line change
Expand Up @@ -273,33 +273,18 @@ fn (mut bwr Browser) send_method(method string, typ MessageType, message Message
method: method
id: id
}
mut raw := ''
data := json.encode(msg)
bwr.ws.write_string(data)!
if typ == .command {
if !msg.wait {
th := spawn bwr.recv_from_command(msg)
return Result{
method: method
state: .pending
th: th
id: id
raw: raw
}
}
return bwr.recv_from_command(msg)!
}
if !msg.wait {
th := spawn bwr.recv_from_event(msg)
th := spawn bwr.recv_method(typ, msg)
return Result{
method: method
state: .pending
th: th
id: id
raw: raw
}
}
return bwr.recv_from_event(msg)!
return bwr.recv_method(typ, msg)!
}

pub fn (mut bwr Browser) send(method string, msg Message) !Result {
Expand All @@ -316,55 +301,45 @@ pub fn (mut bwr Browser) on(method string, msg Message) !Result {
return bwr.send_method(method, .event, msg)
}

pub fn (mut bwr Browser) recv_from_command(msg Message) !Result {
mut raw, id, method := '', msg.id, msg.method
pub fn (mut bwr Browser) recv_method(typ MessageType, msg Message) !Result {
mut data, id, method := map[string]json.Any{}, msg.id, msg.method
mut is_ok := false
for {
select {
data := <-bwr.ch {
json_map := json.decode[json.Any](data)!.as_map()
raw := <-bwr.ch {
data = json.decode[json.Any](raw)!.as_map()
if !isnil(msg.cb) {
msg.cb(Result{ method: method, id: id, raw: data }, msg.ref)!
res := Result{
method: method
id: id
data: data
}
msg.cb(res, msg.ref)!
}
if json_map['id'] or { json.Any(-2) }.int() == id {
raw = data
break
if typ == .command {
if data['id'] or { json.Any(-2) }.int() == id {
is_ok = true
break
}
} else if typ == .event {
if data['method'] or { json.Any('') }.str() == method {
is_ok = true
break
}
}
}
bwr.timeout_recv {
return error('connection failed')
}
}
}
return Result{
method: method
id: id
raw: raw
}
}

pub fn (mut bwr Browser) recv_from_event(msg Message) !Result {
mut raw, id, method := '', msg.id, msg.method
for {
select {
data := <-bwr.ch {
json_map := json.decode[json.Any](data)!.as_map()
if !isnil(msg.cb) {
msg.cb(Result{ method: method, id: id, raw: data }, msg.ref)!
}
if json_map['method'] or { json.Any('') }.str() == method {
raw = data
break
}
}
bwr.timeout_recv {
return error('connection failed')
}
}
if !is_ok {
data = map[string]json.Any{}
}
return Result{
method: method
id: id
raw: raw
data: data
}
}

Expand Down
27 changes: 27 additions & 0 deletions examples/get_title.v
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
import herudi.cdv

fn get_title(mut browser cdv.Browser) !string {
mut tab := browser.new_tab()!

mut page := tab.use_page()!
page.navigate(url: 'https://example.com/')!
page.load_event_fired()!

mut runtime := tab.use_runtime()!
res := runtime.evaluate(expression: 'document.title')!.result()
return res['result']!.as_map()['value']!.str()
}

fn main() {
mut browser := cdv.open_chrome()!

defer { browser.close() }

title := get_title(mut browser) or {
browser.close()
panic(err)
}

assert typeof(title).name == 'string'
assert title.to_lower().contains('example') == true
}
30 changes: 30 additions & 0 deletions examples/inspect_network.v
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
import herudi.cdv

fn inspect_network(mut browser cdv.Browser) ! {
mut tab := browser.new_tab()!

mut page := tab.use_page()!
page.navigate(url: 'https://vlang.io/')!
page.load_event_fired(
cb: fn (res cdv.Result, ref voidptr) ! {
data := res.as_map()
method := data['method'] or { '' }.str()
// see https://chromedevtools.github.io/devtools-protocol/tot/Network/#event-responseReceived
if method == 'Network.responseReceived' {
println(data['params']!.prettify_json_str())
println('\n')
}
}
)!
}

fn main() {
mut browser := cdv.open_chrome()!

defer { browser.close() }

inspect_network(mut browser) or {
browser.close()
panic(err)
}
}
25 changes: 25 additions & 0 deletions examples/save_pdf.v
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
import herudi.cdv

fn save_pdf(mut browser cdv.Browser) ! {
mut tab := browser.new_tab()!

mut page := tab.use_page()!
page.navigate(url: 'https://example.com')!
page.load_event_fired()!

res := page.print_to_pdf()!
res.save('./example.pdf')!

println('success save pdf')
}

fn main() {
mut browser := cdv.open_chrome()!

defer { browser.close() }

save_pdf(mut browser) or {
browser.close()
panic(err)
}
}
37 changes: 11 additions & 26 deletions result.v
Original file line number Diff line number Diff line change
Expand Up @@ -10,51 +10,36 @@ pub enum ResultState {
}

pub struct Result {
pub mut:
mut:
state ResultState = .resolved
pub:
method string
id int
raw string
data map[string]json.Any
th thread !Result
}

fn str_to_map(s string) map[string]json.Any {
return json.decode[json.Any](s) or {
map[string]json.Any{}
}.as_map()
}

pub fn (res Result) as_map() map[string]json.Any {
return str_to_map(res.raw)
return res.data
}

pub fn (res Result) str() string {
return res.raw
return res.data.str()
}

pub fn (res Result) json[T]() !T {
return json.decode[T](res.raw)!
return json.decode[T](res.str())!
}

const save_file_methods = ['Page.captureScreenshot', 'Page.printToPDF']

pub fn (res Result) save(path string) ! {
result := res.as_map()['result']!.as_map()
mut buf, mut is_save := []u8{}, false
if save_file_methods.contains(res.method) {
buf = base64.decode(result['data']!.str())
is_save = true
}
if is_save {
mut f := os.create(path)!
defer {
f.close()
}
f.write(buf)!
return
data := result['data'] or { return error('cannot save file from method "${res.method}"') }
buf := base64.decode(data.str())
mut f := os.create(path)!
defer {
f.close()
}
return error('cannot save from method "${res.method}"')
f.write(buf)!
}

pub fn (res Result) result() map[string]json.Any {
Expand Down

0 comments on commit 9e6efbe

Please sign in to comment.