Created
September 21, 2024 16:14
-
-
Save rybla/a98686895528aa7839e98ffb4bc4894c to your computer and use it in GitHub Desktop.
simple http server in Purescript
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
- console | |
- debug | |
- effect | |
- node-fs | |
- node-http | |
- prelude |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import Prelude | |
import Effect (Effect) | |
import Effect.Aff (launchAff_) | |
import Effect.Class (liftEffect) | |
import Effect.Class.Console as Console | |
import Node.Encoding (Encoding(..)) | |
import Node.EventEmitter (on_, once_) | |
import Node.FS.Sync as FS | |
import Node.HTTP (createServer) | |
import Node.HTTP.IncomingMessage as IncomingMessage | |
import Node.HTTP.OutgoingMessage as OutgoingMessage | |
import Node.HTTP.Server (requestH, toNetServer) | |
import Node.HTTP.ServerResponse as ServerResponse | |
import Node.Net.Server (listenTcp, listeningH) | |
import Node.Path as Path | |
import Node.Stream as Stream | |
host :: String | |
host = "localhost" | |
port :: Int | |
port = 8080 | |
uri_base :: String | |
uri_base = "http://" <> host <> ":" <> show port | |
main :: Effect Unit | |
main = launchAff_ do | |
Console.log "entrypoint: Gos.Server.Main.main" | |
server <- createServer # liftEffect | |
server # toNetServer | |
# once_ listeningH (Console.log $ "listening at " <> uri_base) | |
# liftEffect | |
server | |
# on_ requestH | |
( \in_msg res -> do | |
let out_msg = res # ServerResponse.toOutgoingMessage | |
let out_stream = out_msg # OutgoingMessage.toWriteable | |
let url = in_msg # IncomingMessage.url | |
case in_msg # IncomingMessage.method of | |
"GET" -> do | |
let filepath = "./public" <> url | |
exists <- FS.exists filepath | |
let extname = Path.extname filepath | |
if exists then do | |
out_msg # OutgoingMessage.setHeader "Content-Type" | |
case extname of | |
"" -> "text/html" | |
".html" -> "text/html" | |
".css" -> "text/css" | |
".json" -> "application/json" | |
".png" -> "image/png" | |
_ -> "text/plain" | |
content <- FS.readTextFile UTF8 (filepath <> if extname == "" then "/index.html" else "") | |
Stream.writeString out_stream UTF8 content # void | |
Stream.end out_stream | |
Console.log $ "served " <> filepath | |
else do | |
if extname == "" || extname == ".html" then do | |
out_msg # OutgoingMessage.setHeader "Content-Type" "text/html" | |
content <- FS.readTextFile UTF8 "./public/404.html" | |
Stream.writeString out_stream UTF8 content # void | |
else do | |
ServerResponse.setStatusCode 404 res | |
Stream.end out_stream | |
Console.log $ "not found " <> filepath | |
_ -> pure unit | |
) | |
# liftEffect | |
listenTcp (server # toNetServer) { host, port } # liftEffect |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
servers any file from
./public
, with some handling for different file typesif a
.http
file isn't found, then serves./public/404.html
. if a non-.http
file isn't found, just serves 404 error code.