wsSocket ::
    SocketConfig ->
    Managed (View (Either SocketComms ByteString),
             Controller (Either SocketComms ByteString))
wsSocket c = join $ managed $ \k -> do
    (oC, iC, sealC) <- spawn' unbounded
    (oV, iV, sealV) <- spawn' unbounded

    let handler pending =
            with (managed (withConnection pending)) $ \conn -> do
                aC <- async $ do
                    runEffect $
                        forever (do
                            d <- lift $ WS.receiveData conn
                            yield d) >->
                        Pipes.map Right >->
                        toOutput oC
                    atomically sealC
                aV <- async $ do
                    runEffect $
                        fromInput iV >->
                        until' (Left CloseSocket) >->
                        forever (do
                             x <- await
                             case x of
                                 Left CloseSocket -> do
                                      lift $ WS.sendClose conn ("closing" :: Text)
                                      lift $ putStrLn "CloseSocket!"
                                 Right stream ->
                                      lift $ WS.sendTextData conn stream
                                 _ -> return ())
                    atomically sealV
                link aV
                link aC
                _ <- waitAnyCancel [aV, aC]
                void $ atomically $ send oC (Left ServerClosed)

    aServer <- async $ run (c^.cHost) (c^.cPort) handler
    (void . atomically . send oC) (Left ServerReady)

    result <- k (return
                 ( asSink (void . atomically . send oV)
                 , asInput iC
                 ))
              <* atomically sealC
              <* atomically sealV

    cancel aServer
    return result
wsSocket ::
    SocketConfig ->
    Managed (View (Either SocketComms ByteString),
             Controller (Either SocketComms ByteString))
wsSocket c = join $ managed $ \k -> do
    (oC, iC, sealC) <- spawn' unbounded
    (oV, iV, sealV) <- spawn' unbounded

    let handler pending =
            with (managed (withConnection pending)) $ \conn -> do
                aC <- async $ do
                    runEffect $
                        forever (do
                            d <- lift $ WS.receiveData conn
                            yield d) >->
                        Pipes.map Right >->
                        toOutput oC
                    atomically sealC
                aV <- async $ do
                    runEffect $
                        fromInput iV >->
                        until' (Left CloseSocket) >->
                        forever (do
                             x <- await
                             case x of
                                 Left CloseSocket -> do
                                      lift $ WS.sendClose conn ("closing" :: Text)
                                      lift $ putStrLn "CloseSocket!"
                                 Right stream ->
                                      lift $ WS.sendTextData conn stream
                                 _ -> return ())
                    atomically sealV
                link aV
                link aC
                _ <- waitAnyCancel [aV, aC]
                void $ atomically $ send oC (Left ServerClosed)

    aServer <- async $ run (c^.cHost) (c^.cPort) handler
    (void . atomically . send oC) (Left ServerReady)

    result <- k (return
                 ( asSink (void . atomically . send oV)
                 , asInput iC
                 ))
              <* atomically sealC
              <* atomically sealV

    cancel aServer
    return result
wsSocket c = join $ managed $ \k -> do
    (oC, iC, sealC) <- spawn' unbounded
    (oV, iV, sealV) <- spawn' unbounded

    let handler pending =
            with (managed (withConnection pending)) $ \conn -> do
                aC <- async $ do
                    runEffect $
                        forever (do
                            d <- lift $ WS.receiveData conn
                            yield d) >->
                        Pipes.map Right >->
                        toOutput oC
                    atomically sealC
                aV <- async $ do
                    runEffect $
                        fromInput iV >->
                        until' (Left CloseSocket) >->
                        forever (do
                             x <- await
                             case x of
                                 Left CloseSocket -> do
                                      lift $ WS.sendClose conn ("closing" :: Text)
                                      lift $ putStrLn "CloseSocket!"
                                 Right stream ->
                                      lift $ WS.sendTextData conn stream
                                 _ -> return ())
                    atomically sealV
                link aV
                link aC
                _ <- waitAnyCancel [aV, aC]
                void $ atomically $ send oC (Left ServerClosed)

    aServer <- async $ run (c^.cHost) (c^.cPort) handler
    (void . atomically . send oC) (Left ServerReady)

    result <- k (return
                 ( asSink (void . atomically . send oV)
                 , asInput iC
                 ))
              <* atomically sealC
              <* atomically sealV

    cancel aServer
    return result