1{-# LANGUAGE OverloadedStrings #-}
2import Control.Concurrent
3import Control.Concurrent.Async
6import Network.Wai.Handler.Warp (defaultSettings)
7import Network.Wai.Handler.WarpTLS
8import Network.HTTP.Types (status200)
9import Network.Socket (Socket(..), mkSocket, SocketStatus(..))
10import Blaze.ByteString.Builder (copyByteString)
12import qualified Data.Conduit as C
13import qualified Data.Conduit.List as CL
14import System.Environment (getEnv)
15import System.Posix.Process
16import System.Posix.Signals
18envSocketName = "GRACEFUL_PONG_SOCKET"
20fromSocket2Env sock = [(envSocketName, show (fd, addrFamily, socketType, protocolNumber))]
22 MkSocket fd addrFamily socketType protocolNumber _socketStatus = sock
24handleSIGHUP proc spawn =
25 modifyMVar_ proc $ \oldpid -> do
27 signalProcess lostConnection oldpid
28 status <- waitpid oldpid
29 print (oldpid, status)
33 mstatus <- getProcessStatus False True pid
35 Nothing -> waitpid pid
36 Just status -> return status
38handleSIGTERM proc finish =
40 signalProcess softwareTermination >>
43child (fd, addrFamily, socketType, protocolNumber) = do
44 sock <- mkSocket fd addrFamily socketType protocolNumber Listening
45 putStrLn "https://localhost:3000/"
46 finish <- newEmptyMVar
47 let sighup = Catch $ putMVar finish ()
48 _handler <- installHandler lostConnection sighup Nothing
49 runTLSSocket (TLSSettings "certificate.pem" "key.pem") defaultSettings sock app `race_` takeMVar finish
52 sock <- listenOn $ PortNumber $ toEnum 3000
53 let env = Just $ fromSocket2Env sock
54 spawn = forkProcess $ executeFile "./graceful-pong" False [] env
55 proc <- spawn >>= newMVar
56 finish <- newEmptyMVar
57 let sighup = Catch $ handleSIGHUP proc spawn
58 sigterm = Catch $ handleSIGTERM proc finish
59 _handler <- installHandler lostConnection sighup Nothing
60 _handler <- installHandler softwareTermination sigterm Nothing
64 (getEnv envSocketName >>= child . read) `catch` const parent
67 case rawPathInfo req of
68 "/builder/withlen" -> builderWithLen
69 "/builder/nolen" -> builderNoLen
70 "/file/withlen" -> fileWithLen
71 "/file/nolen" -> fileNoLen
72 "/source/withlen" -> sourceWithLen
73 "/source/nolen" -> sourceNoLen
76builderWithLen = ResponseBuilder
78 [ ("Content-Type", "text/plain")
79 , ("Content-Length", "4")
81 $ copyByteString "PONG"
83builderNoLen = ResponseBuilder
85 [ ("Content-Type", "text/plain")
87 $ copyByteString "PONG"
89sourceWithLen = ResponseSource
91 [ ("Content-Type", "text/plain")
92 , ("Content-Length", "4")
94 $ CL.sourceList [C.Chunk $ copyByteString "PONG"]
96sourceNoLen = ResponseSource
98 [ ("Content-Type", "text/plain")
100 $ CL.sourceList [C.Chunk $ copyByteString "PONG"]
102fileWithLen = ResponseFile
104 [ ("Content-Type", "text/plain")
105 , ("Content-Length", "4")
110fileNoLen = ResponseFile
112 [ ("Content-Type", "text/plain")
117index p = ResponseBuilder status200 [("Content-Type", "text/html")] $ mconcat $ map copyByteString
118 [ "<p><a href='/builder/withlen'>builder withlen</a></p>\n"
119 , "<p><a href='/builder/nolen'>builder nolen</a></p>\n"
120 , "<p><a href='/file/withlen'>file withlen</a></p>\n"
121 , "<p><a href='/file/nolen'>file nolen</a></p>\n"
122 , "<p><a href='/source/withlen'>source withlen</a></p>\n"
123 , "<p><a href='/source/nolen'>source nolen</a></p>\n"
keysesc to close
- j k
- move down, up
- enter
- open
- esc
- back, or up a level
- 1 2 3 4
- readme, files, commits, refs
- /
- filter
- y
- copy the clone command
- c
- compare the chosen commit with another (or shift-click both)
- ?
- show or hide this list