-
Notifications
You must be signed in to change notification settings - Fork 1
/
Copy pathresolver.nim
100 lines (79 loc) · 4.25 KB
/
resolver.nim
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
# Usage: resolver domain.com [domain2.com ... domainN.com]
#
# For those who don't quite understand the async workflow in Nim, you can compile
# with `-d:showLoopLog`.
#
# It is important to understand that within the infinite loop of events you can perform other
# operations that may or may not block the thread.
# Examples:
# 1) you can change the code to resolve 2 domains at a time;
# 2) you can resolve a domain and maintain an IRC connection;
# 3) you can have an HTTP server and a domain resolution.
#
# There are several possibilities.
import std/[asyncdispatch, os, strformat] # Importing modules from stdlib
import ndns # pkg/ndns - Importing the `ndns` package
var isResolvingAnyDns = false # A boolean to know if there is already a domain being resolved
proc resolveDomain(client: DnsClient, strDomain: string) {.async.} =
# Declaring an asynchronous procedure to perform resolution of `strDomain` and print the IPv4
# received as a response. See https://nim-lang.org/docs/asyncdispatch.html#asynchronous-procedures
isResolvingAnyDns = true # Setting to `true` to resolve only one at a time
echo fmt"Resolving `{strDomain}`..."
let allIpv4 = await asyncResolveIpv4(client, strDomain) # Calls the procedure `asyncResolveIpv4`,
# asynchronously, using `await`, which
# also doesn't lock the thread, but makes
# return here when `Future[seq[string]]`
# is ready, which is the return value of
# called procedure.
when defined(showLoopLog):
let domainName = fmt"`{strDomain}`"
else:
let domainName = fmt" "
if len(allIpv4) == 0:
echo fmt"{domainName} did not return IPv4. Possibly it does not exist.{'\n'}"
elif len(allIpv4) == 1:
echo fmt"{domainName} Address:{'\n'} {allIpv4[0]}{'\n'}"
else:
echo fmt"{domainName} Addresses:"
for ip in allIpv4: # Print all IPv4 returned in `allIpv4`
echo fmt" {ip}"
echo ""
isResolvingAnyDns = false # Setting it to `false`, so the event loop can resolve the next domain
proc main() =
let argsCount = paramCount() # https://nim-lang.org/docs/os.html#paramCount
if argsCount == 0:
echo fmt"""Usage:
{getAppFilename().extractFilename} domain.com [domain2.com ... domainN.com]"""
quit(0)
let client = initSystemDnsClient() # https://rockcavera.github.io/nim-ndns/ndns.html#initSystemDnsClient
echo fmt"DNS client initialized using DNS Server: {getIp(client)}{'\n'}"
var
countLoop = 0 # Counter of how many loops it will take to resolve all domains
x = 1 # Current index of passed arguments
while true: # Infinite loop of events. It will resolve only one DNS at a time asynchronously, but
# the loop will continue...
when defined(showLoopLog):
inc(countLoop) # Increasing the counter
echo fmt"Starting loop {countLoop}"
if not isResolvingAnyDns: # If it's not resolving any domain...
while (x <= argsCount) and (paramStr(x) == ""): inc(x) # Skip empty `paramStr(x)`.
if x <= argsCount: # If the index is less than or equal to the number of arguments passed
when defined(showLoopLog):
echo "Before calling `resolveDomain`"
asyncCheck resolveDomain(client, paramStr(x)) # Calls the async procedure `resolveDomain`,
# without blocking the thread, to resolve the
# domain present in `paramStr(x)`.
when defined(showLoopLog):
echo "After calling `resolveDomain`"
inc(x) # Increase index
else:
when defined(showLoopLog):
echo fmt"Work finished in loop {countLoop}"
break # Exits the infinite loop of events as it has no more domains to resolve
if hasPendingOperations(): # https://nim-lang.org/docs/asyncdispatch.html#hasPendingOperations
when defined(showLoopLog):
echo "Calling `poll`..."
poll(15) # https://nim-lang.org/docs/asyncdispatch.html#poll%2Cint
when defined(showLoopLog):
echo fmt"Ending loop {countLoop}{'\n'}"
main()