I want to migrate some existing asynch code to use the chronos module (with AsyncQueue support).
Given the following example code....
If I compile with asyncdispatch module it compiles and runs
If I compile with chronos module it generates the error message documented below.
It looks like the expectations for await are different and are not compatible. (Odd since I thought chronos was built on top of async modules)
What has to change to eliminate the compile error?
Appreciation in advance for any help...
import cdp, json
# When enabled - following code compiles
import asyncdispatch
# When enabled - following code generates the following compile error
# /Users/dennismisener/work/Nim/test.nim(12, 76) template/generic instantiation of `async` from here
# /Users/dennismisener/work/Nim/test.nim(28, 76) template/generic instantiation of `setResult` from here
# /Users/dennismisener/work/Nim/test.nim(15, 21) Error: type mismatch
# Expression: await newTab(browser)
# [1] newTab(browser): Future[base.Tab]
#
# Expected one of (first mismatch at [position]):
# [1] template await[T, E](fut: InternalRaisesFuture[T, E]): T
# [1] template await[T](f: Future[T]): T
# import chronos
# A custom exception for handling CDP errors
type CdpError* = object of CatchableError
# Function to perform a primary web request using CDP
proc fetchPrimaryResponse(browser: Browser, url: string): Future[string] {.async.} =
echo "Fetching primary response for: " & url
try:
let tab = await browser.newTab
echo "new tab created"
await tab.enablePageDomain
echo "Page domain enabled"
discard await tab.navigate(url)
echo "Navigated to URL"
discard await browser.waitForSessionEvent(tab.sessionId, $Page.domContentEventFired)
echo "DOM content loaded"
let content = await tab.evaluate("document.documentElement.outerHTML")
echo "Content fetched"
result = content["result"]["result"]["value"].getStr
except Exception as e:
echo "Error fetching primary response for " & url & ": " & e.msg
raise newException(CdpError, "Failed to fetch primary response for " & url)
proc main() {.async.} =
const SAMPLE_SITE = "https://example.com"
let
browser = await launchBrowser() # Launch a CDP browser instance
response = await browser.fetchPrimaryResponse(SAMPLE_SITE)
echo "Response: ", response.repr
await browser.close
if isMainModule: waitFor main()
chronos's await takes chronos Futures, but browser.newTab (from cdp) returns an asyncdispatch Future.
Unless chronos has some compatibility magic that I don't know about, you need to somehow turn the asyncdispatch Futures returned by cdp into chronos Futures. One way to do this would be to update cdp to support chronos.
Thank you. You are absolutey correct!
The cdp module is incompatible with chronos because cdp is based on asyncdispatch . As such it can't coexist with chronos because of incompatible implementation details (i.e Future internals*) :-(.
Upgrading cdp is probably above my pay grade since I'm an async newbie :-(
Another low tech possibility might be to have:
The primary application could import both of the these modules without the compiler having the issue of incompatible await macro support resulting from differing Future implementations.
Probably messy since all async related code would have to relegated to the two external modules and coordinating interop between them could be complicated.
My immediate plan is to extend the application using asyncdispatch and hopes CDP or another chronos compatible Chrome Devtools Protocol wrapper become available.
Again thanks for your timely feedback.
Upgrading cdp is probably above my pay grade
There is a mini-porting guide here: https://status-im.github.io/nim-chronos/porting.html#asyncdispatch
Usually, the first step is fairly easy which is to replace all import asyncdispatch with import chronos - sometimes, this can "just work" with minor spelling changes and one option for you might be to do just that as a start. It all dependds on which AD features are being used.
What's usually a bigger chunk of work with porting libraries from asyncdispatch is that they tend to completely lack error handling and as a result leak file descriptors, memory and other resources - chronos has tools to aid the process of finding these, but the good news is that it can be done incrementally after the initial step.
To get an idea, compare the first commit of https://github.com/nim-lang/langserver/pull/225/ and the subsequent work that went into error handling mostly.
Another low tech possibility might be to have:
Each of chronos and asyncdispatch needs to process networking events - this implies either running two threads or polling, neither of which are attractive options.