I am able to download a file via sockets between the client / server successfully, however, after making the function call (proc), for the download of the file, I am pulled out of the loop of the Main program and am not able to return back into the loop of the main program. I need some guidance on a way to do return back to the Main program so I can continue making requests within that main while loop.
Essentially when a download is requested, it calls the serve() function and passes it the client for connection and the file name to be downloaded. After connecting to the remote server, it passes the client and filename values to the processclient() function. Which receives and processes the data and filename being downloaded. But once completed, I need a way to regain my access to the Main code within the loop to make further requests.
Here is the client part of the code -
Client -
import os
import net
import strutils
import asyncnet, asyncdispatch, parseutils
proc processClient*(client: AsyncSocket, fileName: string) {.async.} =
var
fileSize: int
counter: int
while not client.isClosed:
echo "Wait file"
var file = open(fileName, fmWrite )
let sizeFileString = await client.recvLine()
discard sizeFileString.parseInt(fileSize)
echo "File Size is " & $fileSize
counter = 0
var dataFut = client.recv(4000)
while true:
yield dataFut
echo "Counter : " & $counter
if counter >= fileSize:
break
else:
if dataFut.finished:
let data = dataFut.read
if data != "":
counter += data.len
file.write(data)
dataFut = client.recv(4000)
else:
echo "No data"
break
else:
echo "Exit"
break
echo "End of file"
file.close
break
client.close()
proc serve*(fileName: string) {.async.} =
var server = newAsyncSocket(buffered=false)
server.setSockOpt(OptReuseAddr, true)
server.bindAddr(Port(5555))
server.listen()
echo "Server running!"
while true:
let client = await server.accept()
echo "New client connected"
asyncCheck processClient(client, fileName)
#asyncCheck serve()
#runForever()
var server: Socket = newSocket()
server.bindAddr(Port(443))
server.listen()
stdout.writeLine("The Sever is now Listening for incoming connections ... ")
var client: Socket = new(Socket)
server.accept(client)
stdout.writeLine("The connection has been established.")
echo "\n"
while true:
stdout.write("Enter a command > ")
let input: string = stdin.readLine()
echo "\n"
if input.startsWith("cmd ") or input.startsWith("exit ") or input.startsWith("getsize ") or input.startsWith("path ") or input.startsWith("screenshot") or input.startsWith("download "):
client.send(input & "\r\n")
if input.startsWith("download "):
var get_name = input[0..^1]
let (dirPath, fileName) = splitPath(get_name)
echo "THIS IS WHAT IS BEING PASSED TO THE FUNCTION: ", fileName
asyncCheck serve(fileName)
runForever()
else:
stdout.writeLine("Command not allowed")
continue
let message: string = client.recvLine()
if ":" in message:
for x in message.split(";"):
stdout.writeLine(x)
echo "\n"
else:
stdout.writeLine(message)
echo "\n"
client.close()
Here ist the corresponding code for the server.
Server -
import net
import osproc
import os
import strutils
let
ip = "192.168.0.10"
port = 443
socket = newSocket()
var cmd : string
if system.hostOS == "windows":
cmd = "cmd /C "
else:
cmd = "/bin/sh -c "
try:
socket.connect(ip, Port(port))
while true:
try:
var input = socket.recvLine()
#echo "Here is the input: ", input
if input == "disconnect" or input == "exit":
socket.send("[+] Exiting Shell\n")
socket.close()
system.quit(0)
elif input.startsWith("getsize"):
let file_path = input[8..^1]
let file_size = os.getFileSize(file_path)
let the_file_size = $file_size
let message = "The file's size is:"
socket.send(message & the_file_size & "\n")
elif input.startsWith("screenshot"):
var powershell : string = "powershell"
var command = "Add-Type -AssemblyName System.Windows.Forms; $screen = [System.Windows.Forms.Screen]::PrimaryScreen.Bounds; $bitmap = New-Object System.Drawing.Bitmap $screen.Width, $screen.Height; $graphics = [System.Drawing.Graphics]::FromImage($bitmap); $graphics.CopyFromScreen($screen.X, $screen.Y, 0, 0, $bitmap.Size); $bitmap.Save('screenshot.png')"
sleep(3000)
let result = os.execShellCmd(powershell & " " & command)
echo "powershell result: ", result
if result != 0:
let failed = "Screenshot failed."
socket.send(failed & "\n")
else:
let succeeded = "Screenshot taken."
socket.send(succeeded & "\n")
elif input.startsWith("path"):
var resp = newSeq[string]()
let my_path = input[5..^1]
for entry in walkDir(my_path,checkDir=true):
resp.add(entry.path)
socket.send(join(resp,";") & "\n")
elif input.startsWith("cmd"):
var command = input[3..^1]
var (result, _) = execCmdEx(cmd & command)
var resp = newSeq[string]()
let lines = result.splitLines()
for line in lines:
resp.add(line)
socket.send(join(resp, ";") & "\n")
elif input.startsWith("download"):
var filename = input[9..^1]
let client: Socket = newSocket()
client.connect("127.0.0.1", Port(5555))
stdout.writeLine("Client: connected to server on address 127.0.0.1:5555")
while true:
echo "This is the file name: ", filename
var data = newString(4000)
let file = open(filename, fmRead)
let size = getFileSize(file)
echo "File size is :" & $size
echo "Send file size"
client.send($size & "\c\L")
echo "Pull ..."
sleep(100)
while true:
let len = file.readBuffer(addr(data[0]), 4000)
setLen(data, len)
if len == 0:
break
else:
echo "Send data size : " & $len
client.send(data)
echo "End of file"
file.close()
break
# Close the client socket
client.close()
except:
echo "test"
#echo "Error: "
#echo getCurrentException().getStackTrace()
#echo getCurrentExceptionMsg()
except:
echo "test"
#echo "Error: "
#echo getCurrentException().getStackTrace()
#echo getCurrentExceptionMsg()
I am able to download a file via sockets
Fine that you had some success. Without studying your actual code, I would suggest that you use an outer loop to archive your desire. In Nim, as in many other programming languages, loops like "while" and "for" can be nested. And note, that in Nim we generally try to avoid global code at all, at least as long as the programs are not tiny. We often use an arbitrary called main function like in C, and only call the main entry point like main() from global code. Having all the code in procs, makes it cleaner, and it may even improve performance, as the C backend can better optimize and don't have to access many global variables.
i don't know exactly what i am talking about...
but
runForever()
in the middle of the code looks like a problem...
asyncCheck serve(fileName)
should maybe be
waitFor serve(fileName)
and you can just remove the runForever()
an echo after the call to the serve should show you when your call returns...
Made the requested changes but not seeing a return back to the main loop. Also put an echo after calling the serve() function, - echo "Returning to the main loop.". Not seeing that echo either.
The loop comes to an end but still not able to get back to the main program loop.
Updated Client-
import os
import net
import strutils
import asyncnet, asyncdispatch, parseutils
proc processClient*(client: AsyncSocket, fileName: string) {.async.} =
var
fileSize: int
counter: int
while not client.isClosed:
echo "Wait file"
var file = open(fileName, fmWrite )
let sizeFileString = await client.recvLine()
discard sizeFileString.parseInt(fileSize)
echo "File Size is " & $fileSize
counter = 0
var dataFut = client.recv(4000)
while true:
yield dataFut
echo "Counter : " & $counter
if counter >= fileSize:
break
else:
if dataFut.finished:
let data = dataFut.read
if data != "":
counter += data.len
file.write(data)
dataFut = client.recv(4000)
else:
echo "No data"
break
else:
echo "Exit"
break
echo "End of file"
file.close
break
client.close()
proc serve*(fileName: string) {.async.} =
var server = newAsyncSocket(buffered=false)
server.setSockOpt(OptReuseAddr, true)
server.bindAddr(Port(5555))
server.listen()
echo "Server running!"
while true:
let client = await server.accept()
echo "New client connected"
asyncCheck processClient(client, fileName)
var server: Socket = newSocket()
server.bindAddr(Port(443))
server.listen()
stdout.writeLine("The Sever is now Listening for incoming connections ... ")
var client: Socket = new(Socket)
server.accept(client)
stdout.writeLine("The connection has been established.")
echo "\n"
proc mainLoop() {.async.} =
while true:
stdout.write("Enter a command > ")
let input: string = stdin.readLine()
echo "\n"
if input.startsWith("cmd ") or input.startsWith("exit ") or input.startsWith("getsize ") or input.startsWith("path ") or input.startsWith("screenshot") or input.startsWith("download "):
client.send(input & "\r\n")
if input.startsWith("download "):
var get_name = input[0..^1]
let (dirPath, fileName) = splitPath(get_name)
echo "THIS IS WHAT IS BEING PASSED TO THE FUNCTION: ", fileName
waitFor serve(fileName)
echo "Returning back to the main loop."
else:
stdout.writeLine("Command not allowed")
continue
let message: string = client.recvLine()
if ":" in message:
for x in message.split(";"):
stdout.writeLine(x)
echo "\n"
else:
stdout.writeLine(message)
echo "\n"
#client.close()
waitFor mainLoop()
The Server code has not been changed.
Here is the current output of both the client and server -
Client Output -
C:\Users\nater\Desktop\nim>client
The Sever is now Listening for incoming connections ...
The connection has been established.
Enter a command > download c:\users\nater\desktop\spring.jpg
THIS IS WHAT IS BEING PASSED TO THE FUNCTION: spring.jpg
Client running!
New client connected
Wait file
File Size is 894902
Counter : 0
Counter : 4000
Counter : 8000
Counter : 12000
Counter : 16000
Counter : 20000
Counter : 24000
Counter : 28000
Counter : 32000
Counter : 36000
Counter : 40000
Counter : 44000
Counter : 48000
Counter : 52000
Counter : 56000
Counter : 60000
Counter : 64000
Counter : 68000
Counter : 72000
Counter : 76000
Counter : 80000
Counter : 84000
Counter : 88000
Counter : 92000
Counter : 96000
Counter : 100000
Counter : 104000
Counter : 108000
Counter : 112000
Counter : 116000
Counter : 120000
Counter : 124000
Counter : 128000
Counter : 132000
Counter : 136000
Counter : 140000
Counter : 144000
Counter : 148000
Counter : 152000
Counter : 156000
Counter : 160000
Counter : 164000
Counter : 168000
Counter : 172000
Counter : 176000
Counter : 180000
Counter : 184000
Counter : 188000
Counter : 192000
Counter : 196000
Counter : 200000
Counter : 204000
Counter : 208000
Counter : 212000
Counter : 216000
Counter : 220000
Counter : 224000
Counter : 228000
Counter : 232000
Counter : 236000
Counter : 240000
Counter : 244000
Counter : 248000
Counter : 252000
Counter : 256000
Counter : 260000
Counter : 264000
Counter : 268000
Counter : 272000
Counter : 276000
Counter : 280000
Counter : 284000
Counter : 288000
Counter : 292000
Counter : 296000
Counter : 300000
Counter : 304000
Counter : 308000
Counter : 312000
Counter : 316000
Counter : 320000
Counter : 324000
Counter : 328000
Counter : 332000
Counter : 336000
Counter : 340000
Counter : 344000
Counter : 348000
Counter : 352000
Counter : 356000
Counter : 360000
Counter : 364000
Counter : 368000
Counter : 372000
Counter : 376000
Counter : 380000
Counter : 384000
Counter : 388000
Counter : 392000
Counter : 396000
Counter : 400000
Counter : 404000
Counter : 408000
Counter : 412000
Counter : 416000
Counter : 420000
Counter : 424000
Counter : 428000
Counter : 432000
Counter : 436000
Counter : 440000
Counter : 444000
Counter : 448000
Counter : 452000
Counter : 456000
Counter : 460000
Counter : 464000
Counter : 468000
Counter : 472000
Counter : 476000
Counter : 480000
Counter : 484000
Counter : 488000
Counter : 492000
Counter : 496000
Counter : 500000
Counter : 504000
Counter : 508000
Counter : 512000
Counter : 516000
Counter : 520000
Counter : 524000
Counter : 528000
Counter : 532000
Counter : 536000
Counter : 540000
Counter : 544000
Counter : 548000
Counter : 552000
Counter : 556000
Counter : 560000
Counter : 564000
Counter : 568000
Counter : 572000
Counter : 576000
Counter : 580000
Counter : 584000
Counter : 588000
Counter : 592000
Counter : 596000
Counter : 600000
Counter : 604000
Counter : 608000
Counter : 612000
Counter : 616000
Counter : 620000
Counter : 624000
Counter : 628000
Counter : 632000
Counter : 636000
Counter : 640000
Counter : 644000
Counter : 648000
Counter : 652000
Counter : 656000
Counter : 660000
Counter : 664000
Counter : 668000
Counter : 672000
Counter : 676000
Counter : 680000
Counter : 684000
Counter : 688000
Counter : 692000
Counter : 696000
Counter : 700000
Counter : 704000
Counter : 708000
Counter : 712000
Counter : 716000
Counter : 720000
Counter : 724000
Counter : 728000
Counter : 732000
Counter : 736000
Counter : 740000
Counter : 744000
Counter : 748000
Counter : 752000
Counter : 756000
Counter : 760000
Counter : 764000
Counter : 768000
Counter : 772000
Counter : 776000
Counter : 780000
Counter : 784000
Counter : 788000
Counter : 792000
Counter : 796000
Counter : 800000
Counter : 804000
Counter : 808000
Counter : 812000
Counter : 816000
Counter : 820000
Counter : 824000
Counter : 828000
Counter : 832000
Counter : 836000
Counter : 840000
Counter : 844000
Counter : 848000
Counter : 852000
Counter : 856000
Counter : 860000
Counter : 864000
Counter : 868000
Counter : 872000
Counter : 876000
Counter : 880000
Counter : 884000
Counter : 888000
Counter : 892000
Counter : 894902
End of file
Server Output -
C:\Users\nater\Desktop\nim>Server
Client: connected to server on address 127.0.0.1:5555
This is the file name: c:\users\nater\desktop\spring.jpg
File size is :894902
Send file size
Pull ...
Send data size : 4000
Send data size : 4000
Send data size : 4000
Send data size : 4000
Send data size : 4000
Send data size : 4000
Send data size : 4000
Send data size : 4000
Send data size : 4000
Send data size : 4000
Send data size : 4000
Send data size : 4000
Send data size : 4000
Send data size : 4000
Send data size : 4000
Send data size : 4000
Send data size : 4000
Send data size : 4000
Send data size : 4000
Send data size : 4000
Send data size : 4000
Send data size : 4000
Send data size : 4000
Send data size : 4000
Send data size : 4000
Send data size : 4000
Send data size : 4000
Send data size : 4000
Send data size : 4000
Send data size : 4000
Send data size : 4000
Send data size : 4000
Send data size : 4000
Send data size : 4000
Send data size : 4000
Send data size : 4000
Send data size : 4000
Send data size : 4000
Send data size : 4000
Send data size : 4000
Send data size : 4000
Send data size : 4000
Send data size : 4000
Send data size : 4000
Send data size : 4000
Send data size : 4000
Send data size : 4000
Send data size : 4000
Send data size : 4000
Send data size : 4000
Send data size : 4000
Send data size : 4000
Send data size : 4000
Send data size : 4000
Send data size : 4000
Send data size : 4000
Send data size : 4000
Send data size : 4000
Send data size : 4000
Send data size : 4000
Send data size : 4000
Send data size : 4000
Send data size : 4000
Send data size : 4000
Send data size : 4000
Send data size : 4000
Send data size : 4000
Send data size : 4000
Send data size : 4000
Send data size : 4000
Send data size : 4000
Send data size : 4000
Send data size : 4000
Send data size : 4000
Send data size : 4000
Send data size : 4000
Send data size : 4000
Send data size : 4000
Send data size : 4000
Send data size : 4000
Send data size : 4000
Send data size : 4000
Send data size : 4000
Send data size : 4000
Send data size : 4000
Send data size : 4000
Send data size : 4000
Send data size : 4000
Send data size : 4000
Send data size : 4000
Send data size : 4000
Send data size : 4000
Send data size : 4000
Send data size : 4000
Send data size : 4000
Send data size : 4000
Send data size : 4000
Send data size : 4000
Send data size : 4000
Send data size : 4000
Send data size : 4000
Send data size : 4000
Send data size : 4000
Send data size : 4000
Send data size : 4000
Send data size : 4000
Send data size : 4000
Send data size : 4000
Send data size : 4000
Send data size : 4000
Send data size : 4000
Send data size : 4000
Send data size : 4000
Send data size : 4000
Send data size : 4000
Send data size : 4000
Send data size : 4000
Send data size : 4000
Send data size : 4000
Send data size : 4000
Send data size : 4000
Send data size : 4000
Send data size : 4000
Send data size : 4000
Send data size : 4000
Send data size : 4000
Send data size : 4000
Send data size : 4000
Send data size : 4000
Send data size : 4000
Send data size : 4000
Send data size : 4000
Send data size : 4000
Send data size : 4000
Send data size : 4000
Send data size : 4000
Send data size : 4000
Send data size : 4000
Send data size : 4000
Send data size : 4000
Send data size : 4000
Send data size : 4000
Send data size : 4000
Send data size : 4000
Send data size : 4000
Send data size : 4000
Send data size : 4000
Send data size : 4000
Send data size : 4000
Send data size : 4000
Send data size : 4000
Send data size : 4000
Send data size : 4000
Send data size : 4000
Send data size : 4000
Send data size : 4000
Send data size : 4000
Send data size : 4000
Send data size : 4000
Send data size : 4000
Send data size : 4000
Send data size : 4000
Send data size : 4000
Send data size : 4000
Send data size : 4000
Send data size : 4000
Send data size : 4000
Send data size : 4000
Send data size : 4000
Send data size : 4000
Send data size : 4000
Send data size : 4000
Send data size : 4000
Send data size : 4000
Send data size : 4000
Send data size : 4000
Send data size : 4000
Send data size : 4000
Send data size : 4000
Send data size : 4000
Send data size : 4000
Send data size : 4000
Send data size : 4000
Send data size : 4000
Send data size : 4000
Send data size : 4000
Send data size : 4000
Send data size : 4000
Send data size : 4000
Send data size : 4000
Send data size : 4000
Send data size : 4000
Send data size : 4000
Send data size : 4000
Send data size : 4000
Send data size : 4000
Send data size : 4000
Send data size : 4000
Send data size : 4000
Send data size : 4000
Send data size : 4000
Send data size : 4000
Send data size : 4000
Send data size : 4000
Send data size : 4000
Send data size : 4000
Send data size : 4000
Send data size : 4000
Send data size : 4000
Send data size : 4000
Send data size : 4000
Send data size : 4000
Send data size : 4000
Send data size : 4000
Send data size : 4000
Send data size : 4000
Send data size : 4000
Send data size : 4000
Send data size : 4000
Send data size : 4000
Send data size : 4000
Send data size : 4000
Send data size : 4000
Send data size : 2902
End of file
Notice the server sends chunks of 4000 to the client and at the end it breaks out of the loop and shows "End of file"
The server is nearly the same receiving an iteration of 4000 and when the file chunks have finished, it breaks out of the loop and shows "End of file". However, the echo statement in the client
waitFor serve(fileName)
echo "Returning back to the main loop."
never shows the "Returning back to the main loop.". And there is no ability to input text, as the cursor will not take input. Please help to resolve.Sorry, my memory is not that great. But I begin to remember now, that I read about Nim's issues with the readline proc in 2017 in the Picheta book. That is why I used var messageFlowVar = spawn stdin.readLine() in
https://ssalewski.de/nimprogramming.html#_the_client_application
I am not absolutely sure if that is the problem, I never really understood that issue, was only mentioned in the Picheta book, but not really explained. As least as far as I can remember.
How soon do you need the working code? Have you a working Python implementation? I may have some time over eastern, that is next weekend. May took at least a full day for me, as I have not done real sockets stuff since 2017 when I did some nimsuggest communication. Only some basics for the book, but all based on existing examples. So maybe it is time to refresh my memory. But not before next weekend, sorry.
Good that you send the whole output from client and server so i could make sure every byte was send ;)
I've spotted another thing
while true:
let client = await server.accept()
echo "New client connected"
asyncCheck processClient(client, fileName)
the while loop is fishy you can't get out of that... with the way you have set it up you kind of accepting multiple clients at the same time. Again asyncCheck does not wait and the while loop continues... so you want most likely use waitFor again and remove the while...
echo "waiting for client..."
let client = await server.accept()
echo "New client connected"
waitFor processClient(client, fileName)
echo "client done"
You can try the additional echos with the while and the asyncCheck. to see what happens... I didn't try it so don't take this for granted...
Saying that you mix up async with with blocking calls... that is not advisable
You should never call blocking functions inside an async block...
So for writing the file you want to use
https://nim-lang.org/docs/asyncfile.html
And for the stdin.readLine you have to dig...
For a starting point
Hey, that seemed to get it a little further than before. I am now getting the echo from the "Returning back to the main loop."
if input.startsWith("download "):
var get_name = input[9..^1]
let (dirPath, fileName) = splitPath(get_name)
echo "THIS IS WHAT IS BEING PASSED TO THE FUNCTION: ", fileName
waitFor serve(fileName)
echo "Returning back to the main loop."
However, after echoing these to the screen, the cursor is blinking but not taking any input.
See output from client.
Client Output -
Enter a command > download c:\users\nater\desktop\thepark.jpg
THIS IS WHAT IS BEING PASSED TO THE FUNCTION: thepark.jpg
Server running!
Waiting for client ...
New client connected.
Wait file
File Size is 1413139
End of file
Client done.
Returning back to the main loop.
The other commands work fine. It's only after the download that it seems to stop responding to text input. The server output is the same.
Server Output -
C:\Users\nater\Desktop\nim>server
Client: connected to server on address 127.0.0.1:5555
This is the file name: c:\users\nater\desktop\thepark.jpg
File size is :1413139
Send file size
Pull ...
End of file
Hi Nate, i am located in europe so we have some time difference...
Thanks for sharing your ideas!
To quote @Stefan_Salewski
Your desired tools will become really complicated, and as it should be a admin support tool, it has to be really robust and reliable.
So i see two options. Keep it as it is and use it for that single person you want to help... Try to make it as solid and beautyfull as you can...
Or you decide to go with the big one, and start from scatch...
For that i would go with a real server part. Admins and users would connect to that server, with their own clients. And the server just acts as a gateway. Here you could learn a lot about async.
The clients could be single threaded blocking boring... it simply does not matter.
If a admin connects to the server he will get a message like
Hello no Users a online
When a user connects all admins or maybe a random one gets a message
User Paul has conncted do you want to help him [y/n]
So when Paul connects he will get a messge
The next available admin will help you, please wait...
So they can chat a bit and the admin can request screenshots,files what ever...
Both sides should be able to end the connection.
I guess a chat tool will be good base for everything, because it has all communication you will need.
So if you want to chat you have a command like
chat Hello Paul
which gets just displayed
if you want a filedownload you have a command like
download some/file/from/paul
This one gets not displayed but triggers the file download. Or it gets additional displayed in light blue so that Paul can see what you are doing...
the answer from pauls side could be
file name data
So you know to save it and not display it
I am just brainstorming... but i guess something like this would work.
If you have something where you think this would not work. Now is the best time to discuss that ;)
by the way you are absolutly right the ports don't matter. But i am reading 443 as html over ssl the ssl part is important because it sounds like secure. But here we don't have ssl security...
cheers, g
Hi Nate, just reversed client/server with loggedin and download without addional socket... sorry the structure is just better
based on @Stefan_Salewski work...
# reverseserver.nim
# see also https://nim-lang.org/docs/asyncnet.html#examples-chat-server
import asyncdispatch,asyncfile,asyncnet,os,strutils,base64,threadpool
const
port = Port(12345)
proc ask(prompt:string): string=
stdout.write(prompt)
let bla = stdin.readLine()
return bla
proc asyncWaitFor[T] (work: FlowVar[T], sleepTime: int = 100):Future[T] {.async.} =
## waits asynchron for a FlowVar to finish
while not work.isReady :
await sleepAsync(sleepTime)
return ^work
proc processCommand(command: string, socket: AsyncSocket){.async.}=
waitFor socket.send(command & "\c\l")
# Receive the number of lines from the client
let line = await socket.recvLine()
echo "Received Message: ", line
var numLines = line.parseInt
echo "Receiving ", numLines, " lines"
# then recv only the amount of lines requested
for _ in 0 .. numLines-1:
let line = await socket.recvLine()
if not command.startsWith("download"):
echo ">> ", line
else:
echo line
let decoded = decode(line)
let work = spawn ask("filename to save?>")
let input = waitFor asyncWaitFor(work)
var file = openAsync(input, fmWrite)
await file.write(decoded)
proc serve() {.async.} =
var server = newAsyncSocket()
server.setSockOpt(OptReuseAddr, true)
server.bindAddr(port)
server.listen()
stdout.writeLine("The Server is now listening for incoming connections ... ")
while true:
let client = await server.accept()
while true:
let work = spawn ask(">")
let input = waitFor asyncWaitFor(work)
waitFor processCommand(input,client)
asyncCheck serve()
runForever()
# reverseclient.nim
import threadpool, asyncdispatch, asyncnet, strutils, base64,asyncfile,os
const
port = Port(12345)
ip = "localhost"
proc doConnect(socket: AsyncSocket, serverAddr: string) {.async.} =
echo("Connecting to ", serverAddr)
await socket.connect(serverAddr, port)
echo("Connected!")
proc processClient(client: AsyncSocket):Future[bool] {.async.} =
while true:
let input = await client.recvLine()
if input.len == 0: return false
if input == "loggedin":
let username = getEnv("USERNAME")
let message = "Logged in user:"
# send length of 1 for one line
await client.send("1\c\L")
await client.send(message & username & "\c\L")
elif input.startsWith("download"):
let cmd = input.split(" ")
if cmd.len == 2:
var my_path = cmd[1]
try:
var file = openAsync(my_path, fmRead)
var bytes = await file.readAll()
let encoded = encode(bytes)
await client.send("1\c\L")
await client.send(encoded & "\c\L")
except:
await client.send("0\c\L")
else:
await client.send("0\c\L")
else:
await client.send("1\c\L")
await client.send("unknown command" & "\c\L")
return true
proc main()=
echo("Chat application started")
var socket = newAsyncSocket()
waitFor doConnect(socket, ip)
stdout.writeLine("The connection has been established.")
var check = true
while check:
check = waitFor processClient(socket)
main()
Looks great! My only concern is firewall issues. The big advantage of reverse is it has no firewall problems. When helping a user it might be difficult to walk them through the process of setting this to go through their firewall. Have you been able to get this to work with the reverse format?
I will work on this tonight to see how we can make this a useful tool so it can be used to help people(:
Thank you for your expertise.
Nate
:) This one is reversed your way... admin input on the server side...
Sorry... was for jumping on this codebase not fixing yours...
I tried to compile the code on both client and server but got on error on each one.
nim-1.6.10libpureconcurrencythreadpool.nim(22, 10) Error: Threadpool requires --threads:on option.
I thought this might be a missing module but not finding any module problem. I will continue to check this.
This message indicates that you need to compile with threads support, e.g.
nim c --threads:on reverseclient.nim
Understood. Will give it another try.
Thanks