Skip to content
Merged
Show file tree
Hide file tree
Changes from 19 commits
Commits
Show all changes
79 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
3f9e253
Docs: Concepts: Clarify noCancel usage.
moigagoo Jun 4, 2026
732e568
Docs: HTTP Client: Remove info about noCancel usage.
moigagoo Jun 4, 2026
94e863b
Docs: HTTP Client: Remove redundant noCancel.
moigagoo Jun 4, 2026
d47faa6
Examples: Remove redundant noCancel.
moigagoo Jun 4, 2026
79a315d
Docs: HTTP Client: Fix info about session purpose.
moigagoo Jun 4, 2026
1c7574e
Docs: HTTP Client: Fix the section about serial vs. concurrent requests.
moigagoo Jun 4, 2026
09dbf48
Examples: HTTP Client: Require Chronos >= 4.2.2.
moigagoo Jun 4, 2026
f680e31
Examples: HTTP Client: Update check[uris] to handle cancellation.
moigagoo Jun 4, 2026
9d17fa5
Docs: HTTP Client: Add info about cancellation policy in check[uris].
moigagoo Jun 4, 2026
f3e69f4
Docs: HTTP Client: Add a general tip about HTTP protocol.
moigagoo Jun 4, 2026
7efaeb7
Examples: HTTP Client: Use valueOr instead of isErr.
moigagoo Jun 4, 2026
d13a54c
Docs: HTTP Client: Remove a weasel word.
moigagoo Jun 4, 2026
a9bfc8f
Docs: HTTP Client: Fix text about error checking on request creation.
moigagoo Jun 4, 2026
4b0addc
Docs: HTTP Client: Split address resolution from async requests.
moigagoo Jun 4, 2026
4d32e20
Merge branch 'master' into feature/httpclient_tutorial
moigagoo Jun 5, 2026
cb269e3
Docs: HTTP Client: Optimize marker lookup to detect valid HTML in che…
moigagoo Jun 5, 2026
25e889f
Docs: HTTP Client: Add finally block to close request.
moigagoo Jun 5, 2026
3a3dff5
Ignore documentation samples technical files.
moigagoo Jun 5, 2026
2596b78
Update .github/workflows/doc.yml
moigagoo Jun 15, 2026
c4700bc
Update .github/workflows/doc.yml
moigagoo Jun 15, 2026
68f87c4
Update .github/workflows/doc.yml
moigagoo Jun 15, 2026
5b8a783
Docs: HTTP Client: Chapter 6: Handle AsyncSemaphoreError in check.
moigagoo Jun 15, 2026
ee5b09c
Docs: HTTP Client: Chapter 6: Update text about AsyncSemaphoreError.
moigagoo Jun 15, 2026
75fdd97
Docs: HTTP Client: Add chapter on session reuse.
moigagoo Jun 15, 2026
c68886a
Docs: HTTP Client: Chapter 6: Rewrite marker lookup to use strings in…
moigagoo Jun 15, 2026
f6c848e
Add readOnce flavor that reads directly to a string.
moigagoo Jun 15, 2026
680c48e
Docs: HTTP Client: Timeout: Use wait instead of withTimeout.
moigagoo Jun 15, 2026
68b53c4
Docs: HTTP Client: Add a page about handling erroneous URIs.
moigagoo Jun 15, 2026
61625f6
Docs: HTTP client: Rewrite chapter about streaming, fix code samples.
moigagoo Jun 15, 2026
d7b202d
Update docs/src/tutorials/http_client/chapter1.md
moigagoo Jun 16, 2026
c854998
Docs: Examples: HTTP Client: Close bodyReader after use.
moigagoo Jun 16, 2026
e931b12
Docs: HTTP Client: Update stdout messages.
moigagoo Jun 16, 2026
396bafc
Docs: Examples: HTTP Client: Close bodyReader *properly*; close reque…
moigagoo Jun 16, 2026
7d0cd02
Docs: HTTP Client: Remove chapter about invalid URI handling and DNS …
moigagoo Jun 16, 2026
5e6c456
Docs: HTTP Client: Add a note aboutt timer drift.
moigagoo Jun 16, 2026
cb65970
Docs: HTTP Client: Add more info about drift.
moigagoo Jun 16, 2026
9a4d749
Remove string-aiming readOnce variant.
moigagoo Jun 16, 2026
3946f0d
Docs: HTTP Client: Add request and response finalization and closing.
moigagoo Jun 16, 2026
735bd7a
Remove compiled binary.
moigagoo Jun 17, 2026
cac1af9
Docs: Examples: HTTP Client: Work around a bug with except in let block.
moigagoo Jun 17, 2026
5c620a3
Docs: HTTP Client: Refactor chapter about streaming.
moigagoo Jun 18, 2026
206a507
Docs: HTTP Client: Fix typo.
moigagoo Jun 18, 2026
627c2d2
Remove compiled binaries.
moigagoo Jun 18, 2026
6263479
Docs: HTTP Client: Update code samples to use refactored findMarker.
moigagoo Jun 18, 2026
23b2578
Docs: HTTP Client: Replace getCurrentExceptionMsg with e.msg.
moigagoo Jun 18, 2026
b61015b
Move examples out of docs.
moigagoo Jun 20, 2026
1b406a7
Docs: HTTP Client: Replace e.msg with getCurrentExceptionMsg.
moigagoo Jun 23, 2026
3bf3057
Merge branch 'master' into feature/httpclient_tutorial
moigagoo Jun 23, 2026
83715b9
Docs: HTTP Client: Chapter 4: Clarify the usage of `except ... as ...…
moigagoo Jun 23, 2026
d5e4c60
Merge branch 'master' into feature/httpclient_tutorial
moigagoo Jun 23, 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 \
Comment thread
moigagoo marked this conversation as resolved.
Outdated
mdbook-toc@0.14.1 \
Comment thread
moigagoo marked this conversation as resolved.
Outdated
mdbook-open-on-gh@2.4.1 \
mdbook-admonish@1.14.0
mdbook-admonish@1.14.0 \
Comment thread
moigagoo marked this conversation as resolved.
Outdated
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"]
19 changes: 19 additions & 0 deletions docs/examples/uptimemon/chapter1.nim
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
import chronos/apps/http/httpclient

proc check(uri: string) {.async.} =
let session = HttpSessionRef.new()

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

if response.status == 200:
echo "[OK] " & uri
else:
echo "[NOK] " & uri & ": " & $response.status
except CatchableError:
Comment thread
moigagoo marked this conversation as resolved.
Outdated
echo "[ERR] " & uri & ": " & getCurrentExceptionMsg()
finally:
await noCancel(session.closeWait())

when isMainModule:
waitFor check("https://google.com")
29 changes: 29 additions & 0 deletions docs/examples/uptimemon/chapter2.nim
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
import chronos/apps/http/httpclient

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

proc check(session: HttpSessionRef, uri: string) {.async.} =
try:
let response = await session.fetch(parseUri(uri))

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

proc check(uris: seq[string]) {.async.} =
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)
35 changes: 35 additions & 0 deletions docs/examples/uptimemon/chapter3.nim
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
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",
]

proc check(session: HttpSessionRef, uri: string) {.async.} =
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 CatchableError:
echo "[ERR] " & uri & ": " & getCurrentExceptionMsg()

proc check(uris: seq[string]) {.async.} =
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)
62 changes: 62 additions & 0 deletions docs/examples/uptimemon/chapter4.nim
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
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/", "https://mock.codes/200",
]

proc findMarker(response: HttpClientResponseRef): Future[bool] {.async.} =
let bodyReader = response.getBodyReader()

var
buffer = newSeq[byte](1024)
fetchedBytes: seq[byte]

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

if bytesRead == 0:
break

fetchedBytes &= buffer

result = "<html" in bytesToString(fetchedBytes)

proc check(session: HttpSessionRef, uri: string) {.async.} =
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()

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
else:
raise newException(AsyncTimeoutError, "Connection timed out")
except CatchableError:
echo "[ERR] " & uri & ": " & getCurrentExceptionMsg()

proc check(uris: seq[string]) {.async.} =
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)
92 changes: 92 additions & 0 deletions docs/examples/uptimemon/chapter5.nim
Original file line number Diff line number Diff line change
@@ -0,0 +1,92 @@
import chronos/apps/http/httpclient

const
ntfyTopic = "X3JIaLZSrFqBJXfJ"
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",
]

proc sendAlert(
session: HttpSessionRef, message: string, priority = 3
) {.async.} =
let
headers = {"Title": "Chronos Uptime Monitor", "Priority": $priority}
body = message.stringToBytes()
request = HttpClientRequestRef.new(
session,
"https://ntfy.sh/" & ntfyTopic,
meth = MethodPost,
headers = headers,
body = body,
)

if request.isOk:
try:
let response = await request.get.send()
await response.closeWait()
except CatchableError:
echo "[WRN] Failed to send alert: " & getCurrentExceptionMsg()

proc findMarker(response: HttpClientResponseRef): Future[bool] {.async.} =
let bodyReader = response.getBodyReader()

var
buffer = newSeq[byte](1024)
fetchedBytes: seq[byte]

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

if bytesRead == 0:
break

fetchedBytes &= buffer

result = "<html" in bytesToString(fetchedBytes)

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

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

let responseFuture = request.get.send()

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

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

if markerFound:
echo "[OK] " & uri
else:
let message = "[NOK] " & uri & ": Not valid HTML"
echo message
await session.sendAlert(message)
else:
let message = "[NOK] " & uri & ": " & $response.status
echo message
await session.sendAlert(message)
else:
raise newException(AsyncTimeoutError, "Connection timed out")
except CatchableError:
let message = "[ERR] " & uri & ": " & getCurrentExceptionMsg()
echo message
await session.sendAlert(message, 4)

proc check(uris: seq[string]) {.async.} =
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)
Loading