Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
29 commits
Select commit Hold shift + click to select a range
9c6b0de
Docs: Tutorials: HTTP Client: Chapter 1.
moigagoo Feb 6, 2026
c0c4e5c
Docs: Tutorials: HTTP Client: Chapter 2 (WIP).
moigagoo Feb 6, 2026
2bd39c0
Docs: Tutorials: HTTP Client: Chapter 2.
moigagoo Feb 7, 2026
7ecd27e
Docs: Uptimemon: Chapter 2: Replace status.im with mock.codes for rel…
moigagoo Feb 9, 2026
a429ab4
Docs: Tutorials: HTTP Client: Chapter 3.
moigagoo Feb 10, 2026
ff0899d
Docs: Tutorials: HTTP Client: Chapter 4 (WIP).
moigagoo Feb 11, 2026
3106871
Docs: Tutorials: HTTP Client: Chapter 4 (WIP).
moigagoo Feb 12, 2026
1591e5b
Docs: Tutorials: HTTP Client: Chapter 4.
moigagoo Feb 12, 2026
a8e520b
Docs: Tutorials: HTTP Client: Chapter 5 (WIP).
moigagoo Feb 13, 2026
a00a3a0
Docs: Tutorials: HTTP Client: Chapter 5.
moigagoo Feb 13, 2026
1d1c98a
Docs: Tutorials: HTTP Client: Chapter 6.
moigagoo Feb 13, 2026
b3bada4
Docs: Tutorials: HTTP Client: Add links to the source code.
moigagoo Feb 14, 2026
9003c05
Build API docs for modules in apps/http.
moigagoo Feb 14, 2026
0b5a75d
Fix exception printing.
moigagoo Feb 16, 2026
3ed384a
Docs: Tutorials: HTTP Client: Chapter 1: Add ref links.
moigagoo Feb 16, 2026
9d7e231
Docs: Tutorials: HTTP Client: Add ref links to all chapters.
moigagoo Feb 16, 2026
25dccf5
CI: Add shiftinclude.
moigagoo Mar 6, 2026
e801920
CI: Add shiftinclude.
moigagoo Mar 6, 2026
2ab3b67
Docs: Chapter 1: Replace hardcoded code snippets with includes.
moigagoo Mar 6, 2026
f0a5e9f
Docs: Uptimemon: Replace line numbers with anchors.
moigagoo Mar 7, 2026
a2312cb
Docs: Uptimemon: Chapter 1: Improve exception handling.
moigagoo Mar 7, 2026
ce9e273
Docs: Uptimemon: Chapter 2: Replace copypasta with includes.
moigagoo Mar 7, 2026
0d73475
Docs: Uptimemon: Chapter 3: Replace copypasta with includes.
moigagoo Mar 7, 2026
ddc599a
Docs: Uptimemon: Chapter 4: Replace copypasta with includes.
moigagoo Mar 9, 2026
927495b
Docs: Uptimemon: Chapter 5: Replace copypasta with includes.
moigagoo Mar 9, 2026
63b6d62
Docs: Uptimemon: Fix missing exceptions.
moigagoo Mar 9, 2026
5930532
Docs: Uptimemon: Chapter 6: Replace copypasta with includes.
moigagoo Mar 9, 2026
3dd9503
HTTP client tutorial: Rename directory to http_client.
moigagoo Mar 27, 2026
1e85d89
HTTP client tutorial: Switch from single files to Nimble projects in …
moigagoo Mar 31, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 6 additions & 5 deletions .github/workflows/doc.yml
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,8 @@ jobs:
build:
timeout-minutes: 20

name: 'Generate & upload documentation'
runs-on: 'ubuntu-latest'
name: "Generate & upload documentation"
runs-on: "ubuntu-latest"
continue-on-error: true
steps:
- name: Checkout
Expand All @@ -24,14 +24,15 @@ jobs:

- name: Install mdBook and preprocessors
run: |
cargo binstall mdbook@0.4.36 \
cargo binstall mdbook@0.4.51 \
mdbook-toc@0.14.1 \
mdbook-open-on-gh@2.4.1 \
mdbook-admonish@1.14.0
mdbook-admonish@1.14.0 \
mdbook-shiftinclude@0.1.0

- uses: jiro4989/setup-nim-action@v1
with:
nim-version: '1.6.20'
nim-version: "1.6.20"

- name: Generate doc
run: |
Expand Down
13 changes: 12 additions & 1 deletion chronos.nimble
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,12 @@ proc run(args, path: string) =
build args, path
exec "build/" & path.splitPath[1]

proc tryExec(cmd: string) =
try:
exec cmd
except Exception as e:
echo e.msg

task examples, "Build examples":
# Build book examples
for file in listFiles("docs/examples"):
Expand Down Expand Up @@ -82,4 +88,9 @@ task test_libbacktrace, "test with libbacktrace":

task docs, "Generate API documentation":
exec "mdbook build docs"
exec nimc & " doc " & "--git.url:https://github.com/status-im/nim-chronos --git.commit:master --outdir:docs/book/api --project chronos"
tryExec nimc & " doc " & "--git.url:https://github.com/status-im/nim-chronos --git.commit:master --outdir:docs/book/api --project chronos"

# Build the docs for modules that aren't part of the main module.
for item in walkDir("chronos/apps/http"):
if item.kind == pcFile and item.path.splitFile().ext == ".nim":
tryExec nimc & " doc " & "--git.url:https://github.com/status-im/nim-chronos --git.commit:master --outdir:docs/book/api/chronos/apps/http " & item.path
12 changes: 9 additions & 3 deletions docs/book.toml
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
[book]
authors = ["Jacek Sieka"]
authors = ["Jacek Sieka", "Constantine Molchanov"]
language = "en"
multilingual = false
src = "src"
Expand All @@ -13,8 +13,14 @@ max-level = 2
[preprocessor.open-on-gh]
command = "mdbook-open-on-gh"
renderer = ["html"]
git-branch = "master"

[preprocessor.admonish]
command = "mdbook-admonish"
assets_version = "3.1.0" # do not edit: managed by `mdbook-admonish install`

[preprocessor.shiftinclude]

[output.html]
git-repository-url = "https://github.com/status-im/nim-chronos/"
git-branch = "master"
additional-css = ["open-in.css"]
additional-css = ["open-in.css", "mdbook-admonish.css"]
37 changes: 37 additions & 0 deletions docs/examples/http_client/chapter1/src/uptimemon.nim
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
# ANCHOR: all
# ANCHOR: import
import chronos/apps/http/httpclient
# ANCHOR_END: import

# ANCHOR: check
proc check(uri: string) {.async: (raises: [CancelledError]).} =
# ANCHOR_END: check
# ANCHOR: session
let session = HttpSessionRef.new()
# ANCHOR_END: session

# ANCHOR: response
try:
let response = await session.fetch(parseUri(uri))
# ANCHOR_END: response

# ANCHOR: status
if response.status == 200:
echo "[OK] " & uri
else:
echo "[NOK] " & uri & ": " & $response.status
# ANCHOR_END: status
# ANCHOR: except
except HttpError:
echo "[ERR] " & uri & ": " & getCurrentExceptionMsg()
# ANCHOR_END: except
# ANCHOR: finally
finally:
await noCancel(session.closeWait())
# ANCHOR_END: finally

# ANCHOR: isMainModule
when isMainModule:
waitFor check("https://google.com")
# ANCHOR_END: isMainModule
# ANCHOR_END: all
8 changes: 8 additions & 0 deletions docs/examples/http_client/chapter1/uptimemon.nimble
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
version = "0.1.0"
author = "Your Name"
description = "HTTP Client Tutorial - Chapter 1"
license = "MIT"
srcDir = "src"
bin = @["uptimemon"]

requires "nim >= 1.6.0", "chronos"
39 changes: 39 additions & 0 deletions docs/examples/http_client/chapter2/src/uptimemon.nim
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
# ANCHOR: all
import chronos/apps/http/httpclient

# ANCHOR: uris
const uris = @[
"https://duckduckgo.com/?q=chronos", "https://mock.codes/403", "http://123.456.78.90"
]
# ANCHOR_END: uris

# ANCHOR: check_uri
proc check(session: HttpSessionRef, uri: string) {.async: (raises: [CancelledError]).} =
try:
let response = await session.fetch(parseUri(uri))

if response.status == 200:
echo "[OK] " & uri
else:
echo "[NOK] " & uri & ": " & $response.status
except HttpError:
echo "[ERR] " & uri & ": " & getCurrentExceptionMsg()
# ANCHOR_END: check_uri

# ANCHOR: check_uris
proc check(uris: seq[string]) {.async: (raises: [CancelledError]).} =
let session = HttpSessionRef.new()
var futures: seq[Future[void]]

for uri in uris:
futures.add(session.check(uri))

await allFutures(futures)
await noCancel(session.closeWait())
# ANCHOR_END: check_uris

# ANCHOR: isMainModule
when isMainModule:
waitFor check(uris)
# ANCHOR_END: isMainModule
# ANCHOR_END: all
8 changes: 8 additions & 0 deletions docs/examples/http_client/chapter2/uptimemon.nimble
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
version = "0.1.0"
author = "Your Name"
description = "HTTP Client Tutorial - Chapter 2"
license = "MIT"
srcDir = "src"
bin = @["uptimemon"]

requires "nim >= 1.6.0", "chronos"
39 changes: 39 additions & 0 deletions docs/examples/http_client/chapter3/src/uptimemon.nim
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
# ANCHOR: all
import chronos/apps/http/httpclient

const uris = @[
"https://duckduckgo.com/?q=chronos", "https://mock.codes/403", "http://123.456.78.90",
"http://10.255.255.1",
]

# ANCHOR: check
proc check(session: HttpSessionRef, uri: string) {.async: (raises: [CancelledError]).} =
try:
let responseFuture = session.fetch(parseUri(uri))

if await responseFuture.withTimeout(5.seconds):
let response = responseFuture.read()

if response.status == 200:
echo "[OK] " & uri
else:
echo "[NOK] " & uri & ": " & $response.status
else:
raise newException(AsyncTimeoutError, "Connection timed out")
except HttpError, FuturePendingError, AsyncTimeoutError:
echo "[ERR] " & uri & ": " & getCurrentExceptionMsg()
# ANCHOR_END: check

proc check(uris: seq[string]) {.async: (raises: [CancelledError]).} =
let session = HttpSessionRef.new()
var futures: seq[Future[void]]

for uri in uris:
futures.add(session.check(uri))

await allFutures(futures)
await noCancel(session.closeWait())

when isMainModule:
waitFor check(uris)
# ANCHOR_END: all
8 changes: 8 additions & 0 deletions docs/examples/http_client/chapter3/uptimemon.nimble
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
version = "0.1.0"
author = "Your Name"
description = "HTTP Client Tutorial - Chapter 3"
license = "MIT"
srcDir = "src"
bin = @["uptimemon"]

requires "nim >= 1.6.0", "chronos"
50 changes: 50 additions & 0 deletions docs/examples/http_client/chapter4_1/src/uptimemon.nim
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
# ANCHOR: all
import chronos/apps/http/httpclient

const uris = @[
"https://duckduckgo.com/?q=chronos", "https://mock.codes/403", "http://123.456.78.90",
"http://10.255.255.1", "https://html.spec.whatwg.org/",
]

proc check(session: HttpSessionRef, uri: string) {.async: (raises: [CancelledError]).} =
try:
let
# ANCHOR: request
request = HttpClientRequestRef.new(session, uri)
# ANCHOR_END: request

# ANCHOR: error_check
if request.isErr:
raise newException(HttpRequestError, request.error)

let
# ANCHOR_END: error_check

# ANCHOR: response
responseFuture = request.value.send()
# ANCHOR_END: response
if await responseFuture.withTimeout(5.seconds):
let response = responseFuture.read()

if response.status == 200:
echo "[OK] " & uri
else:
echo "[NOK] " & uri & ": " & $response.status
else:
raise newException(AsyncTimeoutError, "Connection timed out")
except HttpError, FuturePendingError, AsyncTimeoutError:
echo "[ERR] " & uri & ": " & getCurrentExceptionMsg()

proc check(uris: seq[string]) {.async: (raises: [CancelledError]).} =
let session = HttpSessionRef.new()
var futures: seq[Future[void]]

for uri in uris:
futures.add(session.check(uri))

await allFutures(futures)
await noCancel(session.closeWait())

when isMainModule:
waitFor check(uris)
# ANCHOR_END: all
8 changes: 8 additions & 0 deletions docs/examples/http_client/chapter4_1/uptimemon.nimble
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
version = "0.1.0"
author = "Your Name"
description = "HTTP Client Tutorial - Chapter 4.1"
license = "MIT"
srcDir = "src"
bin = @["uptimemon"]

requires "nim >= 1.6.0", "chronos"
90 changes: 90 additions & 0 deletions docs/examples/http_client/chapter4_2/src/uptimemon.nim
Original file line number Diff line number Diff line change
@@ -0,0 +1,90 @@
# ANCHOR: all
import chronos/apps/http/httpclient

# ANCHOR: urls
const uris = @[
"https://duckduckgo.com/?q=chronos", "https://mock.codes/403", "http://123.456.78.90",
"http://10.255.255.1", "https://html.spec.whatwg.org/", "https://mock.codes/200",
]
# ANCHOR_END: urls

# ANCHOR: findMarker
proc findMarker(
response: HttpClientResponseRef
): Future[bool] {.
async: (raises: [HttpUseClosedError, AsyncStreamError, CancelledError])
.} =
# ANCHOR_END: findMarker
# ANCHOR: bodyReader
let bodyReader = response.getBodyReader()
# ANCHOR_END: bodyReader

# ANCHOR: vars
var
buffer = newSeq[byte](1024)
fetchedBytes: seq[byte]
# ANCHOR_END: vars

# ANCHOR: while
while not result and len(fetchedBytes) <= 10 * 1024:
# ANCHOR_END: while
# ANCHOR: read_bytes
let bytesRead = await bodyReader.readOnce(addr(buffer[0]), len(buffer))
# ANCHOR_END: read_bytes

# ANCHOR: bytes_check
if bytesRead == 0:
break
# ANCHOR_END: bytes_check

# ANCHOR: fetchedBytes
fetchedBytes &= buffer
# ANCHOR_END: fetchedBytes

# ANCHOR: result
result = "<html" in bytesToString(fetchedBytes)
# ANCHOR_END: result

proc check(session: HttpSessionRef, uri: string) {.async: (raises: [CancelledError]).} =
try:
let request = HttpClientRequestRef.new(session, uri)

if request.isErr:
raise newException(HttpRequestError, request.error)

let responseFuture = request.value.send()

if await responseFuture.withTimeout(5.seconds):
let response = responseFuture.read()

# ANCHOR: url_response
if response.status == 200:
let markerFound = await findMarker(response)

if markerFound:
echo "[OK] " & uri
else:
echo "[NOK] " & uri & ": Not valid HTML"
else:
echo "[NOK] " & uri & ": " & $response.status
# ANCHOR_END: url_response
else:
raise newException(AsyncTimeoutError, "Connection timed out")
# ANCHOR: except
except HttpError, FuturePendingError, AsyncTimeoutError, AsyncStreamError:
# ANCHOR_END: except
echo "[ERR] " & uri & ": " & getCurrentExceptionMsg()

proc check(uris: seq[string]) {.async: (raises: [CancelledError]).} =
let session = HttpSessionRef.new()
var futures: seq[Future[void]]

for uri in uris:
futures.add(session.check(uri))

await allFutures(futures)
await noCancel(session.closeWait())

when isMainModule:
waitFor check(uris)
# ANCHOR_END: all
8 changes: 8 additions & 0 deletions docs/examples/http_client/chapter4_2/uptimemon.nimble
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
version = "0.1.0"
author = "Your Name"
description = "HTTP Client Tutorial - Chapter 4.2"
license = "MIT"
srcDir = "src"
bin = @["uptimemon"]

requires "nim >= 1.6.0", "chronos"
Loading
Loading