Hello I'm a new user to nim and tryng to build some demo app to learn the language.
I have a question about the ftpclient library, i've tried to make a connection with this library and also with the other asyncftpclient library but I get always the following error: Error: unhandled exception: Expected reply '230' or '331' got: 220-#
I've tried with this code for the asyncftpclient, but i get always this error
import asyncftpclient, asyncnet, asyncdispatch
var ftp = newAsyncFtpclient(address="ftp.example.com", port= (Port(21)), user = "USER", pass = "PASSWORD")
proc main(ftp: AsyncFtpClient) {.async.} =
echo ("starting")
await ftp.connect()
echo await ftp.send("SYST\n")
echo await ftp.pwd()
echo await ftp.listDirs()
echo ("finished")
waitFor main(ftp)
Can you please let me what operation i need to do to make it accept the first 220 message from ftp server?
Seems that i find a possible solution for this. The ftpclient and asyncftpclient wait for integers as ftp response code but if the server as in my case responds as: 220- # this is a string and the library sends an error because expects 230 or 331 integers.
I find that strutils.parseInt can be useful to catch the integer inside the response code, but unfortunately i've still not found how to modify the library to resolve this.
Your code works fine for me. I simply installed vsftpd on my Ubuntu box and changed the address to point to it, and it connects and displays a list of directories.
What version of Nim are you on? I'm on the latest built from github, which might be why I'm seeing different results if you are on the latest stable.
In asyncftpclient i changed the proc procedure to
proc assertReply(received: TaintedString, expected: varargs[string]) =
for i in items(expected):
# Skip if server returns 220 message
if received.string.startsWith("220"): return
elif received.string.startsWith(i): return
raise newException(ReplyError,
"Expected reply '$1' got: $2" %
[expected.join("' or '"), received.string])
and i'm able to connect to the server, but for a strange reason, every successive ftp command I send get unxpected server response taken from previous messages.
For example in previous code i posted i get Expected reply '257' got: 331 User test OK. Password required
It's like the response messages are not in sync with the ftp response.
Finally i managed this to work on ftpclient and asyncftpclient with the following change (forgot my previous post):
On Asyncftpclient
proc connect*(ftp: AsyncFtpClient) {.async.} =
## Connect to the FTP server specified by ``ftp``.
await ftp.csock.connect(ftp.address, ftp.port)
var reply = await ftp.expectReply()
if reply.startsWith("120"):
# 120 Service ready in nnn minutes.
# We wait until we receive 220.
reply = await ftp.expectReply()
# Handle 220 messages from the server
if reply.startsWith("220"):
assertReply(reply, "220")
while reply.continuesWith("-", 3): # handle multiline 220 message
assertReply(reply, "220")
reply = await ftp.expectReply()
....
on ftpclient
proc connect*[T](ftp: FtpBase[T]) =
## Connect to the FTP server specified by ``ftp``.
when T is AsyncSocket:
blockingOperation(ftp.csock):
ftp.csock.connect(ftp.address, ftp.port)
elif T is Socket:
ftp.csock.connect(ftp.address, ftp.port)
else:
{.fatal: "Incorrect socket instantiation".}
# TODO: Handle 120? or let user handle it.
assertReply ftp.expectReply(), "220"
var reply = ftp.expectReply()
if reply.startsWith("120"):
# 120 Service ready in nnn minutes.
# We wait until we receive 220.
reply = ftp.expectReply()
# Handle 220 messages from the server
if reply.startsWith("220"):
assertReply ftp.expectReply(), "220"
while reply.continuesWith("-", 3): # handle multiline 220 message
assertReply ftp.expectReply(), "220"
reply = ftp.expectReply()
....
Not sure if there is a more elegant way to do this, but i tested on two ftp servers that return multiple 220 messages and it works.
after several researches on the net i found that 220 error message add a dash "-" character for multiline messages
If this code can be useful for everyone i can put a pull request for inclusion
p.s. NIM ROCKS!
EDIT: Implemented e more nice version