I’m stuck on Stage #AP6.
I’ve been using the Python asyncio
library to handle concurrent connections for an earlier stage of my project. I’ve updated my code to fit the new challenge requirements, but I’m running into an error I can’t figure out.
I’d prefer to stick with asyncio
rather than switching to threading. Can you help me troubleshoot and fix the issue with my asyncio
setup?
Here are my logs:
remote: Running tests on your code. Logs should appear shortly...
remote:
remote: [compile] Moved ./.codecrafters/run.sh → ./your_program.sh
remote: [compile] Compilation successful.
remote:
remote: Debug = true
remote:
remote: [tester::#AP6] Running tests for Stage #AP6 (Return a file)
remote: [tester::#AP6] Running program
remote: [tester::#AP6] $ ./your_program.sh --directory /tmp/data/codecrafters.io/http-server-tester/
remote: [tester::#AP6] Testing existing file
remote: [tester::#AP6] Creating file pineapple_strawberry_apple_banana in /tmp/data/codecrafters.io/http-server-tester/
remote: [tester::#AP6] File Content: "strawberry raspberry orange grape pineapple banana orange pineapple"
remote: [your_program] Usage: python app.py --directory=<directory>
remote: [tester::#AP6] Failed to create connection: dial tcp [::1]:4221: connect: connection refused
remote: [tester::#AP6] Test failed
remote: [tester::#AP6] Terminating program
remote: [tester::#AP6] Program terminated successfully
And here’s a snippet of my code:
import asyncio
import sys
import os
async def handle_client(reader, writer):
request_data = await reader.read(1024)
request_lines = request_data.decode().split("\r\n")
if len(request_lines) > 0:
request_line = request_lines[0]
parts = request_line.split(" ")
if len(parts) > 1:
method, path = parts[0], parts[1]
if path == "/":
response = build_response("200 OK")
elif path.startswith("/user-agent"):
user_agent = None
for line in request_lines[1:]:
if line.startswith("User-Agent:"):
user_agent = line.split(": ", 1)[1]
break
if user_agent:
response = build_response("200 OK", content_type="text/plain", body=user_agent.encode())
else:
response = build_response("400 Bad Request", body=b"Bad Request")
elif path.startswith("/files"):
filename = path[len("/files/"):]
file_path = os.path.join(directory, filename)
print(f"Requested file path: {file_path}")
response = await read_file(file_path)
else:
response = build_response("404 Not Found", body=b"Not Found")
writer.write(response)
await writer.drain()
writer.close()
await writer.wait_closed()
async def read_file(file_path):
loop = asyncio.get_running_loop()
try:
with open(file_path, 'rb') as f:
file_contents = await loop.run_in_executor(None, f.read)
return build_response("200 OK", content_type="application/octet-stream", body=file_contents)
except FileNotFoundError:
return build_response("404 Not Found", body=b"File not found")
def build_response(status_code, content_type="text/plain", body=b""):
headers = [
f"HTTP/1.1 {status_code}",
f"Content-Type: {content_type}",
f"Content-Length: {len(body)}",
"", # End of headers
]
headers_str = "\r\n".join(headers)
return headers_str.encode() + b"\r\n" + body
async def main():
global directory
if len(sys.argv) != 3 or not sys.argv[1].startswith("--directory="):
print("Usage: python app.py --directory=<directory>")
return
directory = sys.argv[1].split("=", 1)[1]
if not os.path.isdir(directory):
print(f"Directory does not exist or is not a directory: {directory}")
return
server = await asyncio.start_server(handle_client, "localhost", 4221)
async with server:
await server.serve_forever()
if __name__ == "__main__":
asyncio.run(main())