mirror of
https://github.com/NotAShelf/rafmonad.git
synced 2024-11-22 05:10:46 +00:00
initial commit
This commit is contained in:
parent
21a67a4330
commit
ecc5e51f91
8 changed files with 144 additions and 0 deletions
1
.envrc
Normal file
1
.envrc
Normal file
|
@ -0,0 +1 @@
|
|||
use flake . --builders ""
|
3
.gitignore
vendored
3
.gitignore
vendored
|
@ -21,3 +21,6 @@ cabal.project.local
|
|||
cabal.project.local~
|
||||
.HTF/
|
||||
.ghc.environment.*
|
||||
|
||||
# Nix
|
||||
result/
|
||||
|
|
12
README.md
Normal file
12
README.md
Normal file
|
@ -0,0 +1,12 @@
|
|||
# rafmonad
|
||||
|
||||
An annoyingly simple webserver written in Haskell. Serves a `.txt` file as plaintext on
|
||||
`http://localhost:3000`. Not configurable, has no logging or error handling. Written
|
||||
because I can.
|
||||
|
||||
|
||||
## Using
|
||||
|
||||
Don't.
|
||||
|
||||
|
1
contents.txt
Normal file
1
contents.txt
Normal file
|
@ -0,0 +1 @@
|
|||
Hello, world!
|
24
flake.lock
Normal file
24
flake.lock
Normal file
|
@ -0,0 +1,24 @@
|
|||
{
|
||||
"nodes": {
|
||||
"nixpkgs": {
|
||||
"locked": {
|
||||
"lastModified": 1708118438,
|
||||
"narHash": "sha256-kk9/0nuVgA220FcqH/D2xaN6uGyHp/zoxPNUmPCMmEE=",
|
||||
"path": "/nix/store/bg5fbkfa5x53clcjf4p5p92k1l3w8x38-source",
|
||||
"rev": "5863c27340ba4de8f83e7e3c023b9599c3cb3c80",
|
||||
"type": "path"
|
||||
},
|
||||
"original": {
|
||||
"id": "nixpkgs",
|
||||
"type": "indirect"
|
||||
}
|
||||
},
|
||||
"root": {
|
||||
"inputs": {
|
||||
"nixpkgs": "nixpkgs"
|
||||
}
|
||||
}
|
||||
},
|
||||
"root": "root",
|
||||
"version": 7
|
||||
}
|
46
flake.nix
Normal file
46
flake.nix
Normal file
|
@ -0,0 +1,46 @@
|
|||
{
|
||||
description = "rafmonad: a annoyingly simple webserver";
|
||||
inputs.nixpkgs.url = "github:NixOS/nixpkgs/nixpkgs-unstable";
|
||||
|
||||
outputs = {
|
||||
self,
|
||||
nixpkgs,
|
||||
}: let
|
||||
supportedSystems = ["x86_64-linux"];
|
||||
forAllSystems = f: nixpkgs.lib.genAttrs supportedSystems (system: f system);
|
||||
nixpkgsFor = forAllSystems (system:
|
||||
import nixpkgs {
|
||||
inherit system;
|
||||
overlays = [self.overlays.default];
|
||||
});
|
||||
in {
|
||||
overlays = final: _prev: {
|
||||
rafmonad = final.haskellPackages.callCabal2nix "rafmonad" ./. {};
|
||||
default = self.overlays.rafmonad;
|
||||
};
|
||||
|
||||
packages = forAllSystems (system: {
|
||||
inherit (nixpkgsFor.${system}) rafmonad;
|
||||
default = nixpkgsFor.${system}.rafmonad;
|
||||
});
|
||||
|
||||
checks = self.packages;
|
||||
|
||||
devShell = forAllSystems (system: let
|
||||
inherit (nixpkgsFor.${system}) haskellPackages;
|
||||
in
|
||||
haskellPackages.shellFor {
|
||||
withHoogle = true;
|
||||
|
||||
packages = _: [self.packages.${system}.rafmonad];
|
||||
buildInputs = with haskellPackages; [
|
||||
haskell-language-server
|
||||
ghcid
|
||||
cabal-install
|
||||
];
|
||||
|
||||
# Change the prompt to show that you are in a devShell
|
||||
shellHook = "export PS1='\\e[1;34mDEV ~ > \\e[0m'";
|
||||
});
|
||||
};
|
||||
}
|
9
package.yaml
Normal file
9
package.yaml
Normal file
|
@ -0,0 +1,9 @@
|
|||
dependencies:
|
||||
- base >= 4.6
|
||||
- bytestring
|
||||
- http2
|
||||
- network
|
||||
- async
|
||||
executables:
|
||||
rafmonad:
|
||||
main: src/net.hs
|
48
src/net.hs
Normal file
48
src/net.hs
Normal file
|
@ -0,0 +1,48 @@
|
|||
module Main where
|
||||
|
||||
import Network.Socket
|
||||
import Network.Socket.ByteString (sendAll)
|
||||
import Control.Monad (forever)
|
||||
import qualified System.IO as IO (Handle, hGetLine, hPutStr, hFlush, hClose)
|
||||
import System.IO (readFile)
|
||||
import Data.ByteString.Char8 as B (pack)
|
||||
|
||||
main :: IO ()
|
||||
main = withSocketsDo $ do
|
||||
addr <- resolve "127.0.0.1" "3000" -- listen on port 3000
|
||||
open addr
|
||||
|
||||
resolve :: HostName -> ServiceName -> IO AddrInfo
|
||||
resolve host port = do
|
||||
let hints = defaultHints { addrFlags = [AI_PASSIVE]
|
||||
, addrSocketType = Stream
|
||||
}
|
||||
head <$> getAddrInfo (Just hints) (Just host) (Just port)
|
||||
|
||||
open :: AddrInfo -> IO ()
|
||||
open addr = do
|
||||
sock <- socket (addrFamily addr) (addrSocketType addr) (addrProtocol addr)
|
||||
setSocketOption sock ReuseAddr 1
|
||||
bind sock $ addrAddress addr
|
||||
listen sock 10
|
||||
-- putting the log header manually is funny
|
||||
-- but I don't want to define anything to proramatically
|
||||
-- prepend the log header to the log message
|
||||
-- since I do not log anything else *yet*
|
||||
putStrLn "[LOG] Listening on port: 3000" -- maybe the port needs to be configurable
|
||||
forever $ do
|
||||
(conn, _) <- accept sock
|
||||
handleRequest conn
|
||||
|
||||
drainHeaders :: IO.Handle -> IO ()
|
||||
drainHeaders h = do
|
||||
line <- IO.hGetLine h
|
||||
if line == "\r" then return () else drainHeaders h
|
||||
|
||||
handleRequest :: Socket -> IO ()
|
||||
handleRequest conn = do
|
||||
content <- readFile "contents.txt"
|
||||
let response = "HTTP/2.1 200 OK\r\nContent-Type: text/plain\r\n\r\n" ++ content
|
||||
sendAll conn $ B.pack response
|
||||
close conn
|
||||
|
Loading…
Reference in a new issue