on master help sign in
Remove servant-jssadle (moved to own repository)
commit21e6000b09443e011c9d683898d634a9a3d6f9f8 authorOleg Grenrus <oleg.grenrus@iki.fi> dateFri 10 Jan 2020, 01:20 (7 years ago) parent831f46a
11 files changed−726
.travis.yml−24 cabal.project−14 servant-jsaddle/CHANGELOG.md−4 servant-jsaddle/LICENSE−30 servant-jsaddle/README.md−15 servant-jsaddle/Setup.hs−2 servant-jsaddle/servant-jsaddle.cabal−125 servant-jsaddle/src/Servant/Client/Internal/JSaddleXhrClient.hs−311 servant-jsaddle/src/Servant/Client/JSaddle.hs−20 servant-jsaddle/test/Servant/Client/JSaddleSpec.hs−173 servant-jsaddle/test/Spec.hs−8
.travis.yml−24
@@ -157,18 +157,6 @@ install:
157157 echo "allow-newer: io-streams-1.5.1.0:network" >> cabal.project
158158 echo "allow-newer: io-streams-1.5.1.0:primitive" >> cabal.project
159159 echo "allow-newer: openssl-streams-1.2.2.0:network" >> cabal.project
160− echo "allow-newer: jsaddle-0.9.6.0:lens" >> cabal.project
161− echo "allow-newer: jsaddle-0.9.6.0:primitive" >> cabal.project
162− echo "allow-newer: jsaddle-0.9.6.0:time" >> cabal.project
163− echo "allow-newer: jsaddle-dom-0.9.3.1:base" >> cabal.project
164− echo "allow-newer: jsaddle-dom-0.9.3.1:base-compat" >> cabal.project
165− echo "allow-newer: jsaddle-dom-0.9.3.1:Cabal" >> cabal.project
166− echo "allow-newer: jsaddle-dom-0.9.3.1:lens" >> cabal.project
167− echo "allow-newer: jsaddle-dom-0.9.3.2:base" >> cabal.project
168− echo "allow-newer: jsaddle-dom-0.9.3.2:base-compat" >> cabal.project
169− echo "allow-newer: jsaddle-dom-0.9.3.2:Cabal" >> cabal.project
170− echo "allow-newer: jsaddle-dom-0.9.3.2:lens" >> cabal.project
171− echo "allow-newer: jsaddle-warp-0.9.6.0:time" >> cabal.project
172160 echo "optimization: False" >> cabal.project
173161 - "for pkg in $($HCPKG list --simple-output); do echo $pkg | sed 's/-[^-]*$//' | (grep -vE -- '^(cookbook-basic-auth|cookbook-basic-streaming|cookbook-curl-mock|cookbook-db-postgres-pool|cookbook-file-upload|cookbook-generic|cookbook-pagination|cookbook-structuring-apis|cookbook-testing|cookbook-using-custom-monad|cookbook-using-free-client|servant|servant-client|servant-client-core|servant-conduit|servant-docs|servant-foreign|servant-http-streams|servant-machines|servant-pipes|servant-server|tutorial)$' || true) | sed 's/^/constraints: /' | sed 's/$/ installed/' >> cabal.project.local; done"
174162 - cat cabal.project || true
@@ -271,18 +259,6 @@ script:
271259 echo "allow-newer: io-streams-1.5.1.0:network" >> cabal.project
272260 echo "allow-newer: io-streams-1.5.1.0:primitive" >> cabal.project
273261 echo "allow-newer: openssl-streams-1.2.2.0:network" >> cabal.project
274− echo "allow-newer: jsaddle-0.9.6.0:lens" >> cabal.project
275− echo "allow-newer: jsaddle-0.9.6.0:primitive" >> cabal.project
276− echo "allow-newer: jsaddle-0.9.6.0:time" >> cabal.project
277− echo "allow-newer: jsaddle-dom-0.9.3.1:base" >> cabal.project
278− echo "allow-newer: jsaddle-dom-0.9.3.1:base-compat" >> cabal.project
279− echo "allow-newer: jsaddle-dom-0.9.3.1:Cabal" >> cabal.project
280− echo "allow-newer: jsaddle-dom-0.9.3.1:lens" >> cabal.project
281− echo "allow-newer: jsaddle-dom-0.9.3.2:base" >> cabal.project
282− echo "allow-newer: jsaddle-dom-0.9.3.2:base-compat" >> cabal.project
283− echo "allow-newer: jsaddle-dom-0.9.3.2:Cabal" >> cabal.project
284− echo "allow-newer: jsaddle-dom-0.9.3.2:lens" >> cabal.project
285− echo "allow-newer: jsaddle-warp-0.9.6.0:time" >> cabal.project
286262 echo "optimization: False" >> cabal.project
287263 - "for pkg in $($HCPKG list --simple-output); do echo $pkg | sed 's/-[^-]*$//' | (grep -vE -- '^(cookbook-basic-auth|cookbook-basic-streaming|cookbook-curl-mock|cookbook-db-postgres-pool|cookbook-file-upload|cookbook-generic|cookbook-pagination|cookbook-structuring-apis|cookbook-testing|cookbook-using-custom-monad|cookbook-using-free-client|servant|servant-client|servant-client-core|servant-conduit|servant-docs|servant-foreign|servant-http-streams|servant-machines|servant-pipes|servant-server|tutorial)$' || true) | sed 's/^/constraints: /' | sed 's/$/ installed/' >> cabal.project.local; done"
288264 - cat cabal.project || true
cabal.project−14
@@ -61,20 +61,6 @@ allow-newer: openssl-streams-1.2.2.0:network
6161-- https://github.com/nurpax/sqlite-simple/issues/74
6262constraints: sqlite-simple < 0
6363
64−-- jsaddle
65−allow-newer: jsaddle-0.9.6.0:lens
66−allow-newer: jsaddle-0.9.6.0:primitive
67−allow-newer: jsaddle-0.9.6.0:time
68−allow-newer: jsaddle-dom-0.9.3.1:base
69−allow-newer: jsaddle-dom-0.9.3.1:base-compat
70−allow-newer: jsaddle-dom-0.9.3.1:Cabal
71−allow-newer: jsaddle-dom-0.9.3.1:lens
72−allow-newer: jsaddle-dom-0.9.3.2:base
73−allow-newer: jsaddle-dom-0.9.3.2:base-compat
74−allow-newer: jsaddle-dom-0.9.3.2:Cabal
75−allow-newer: jsaddle-dom-0.9.3.2:lens
76−allow-newer: jsaddle-warp-0.9.6.0:time
77−
7864constraints: base-compat ^>=0.11
7965
8066-- needed for doctests
servant-jsaddle/CHANGELOG.mddeleted−4
@@ -1,4 +0,0 @@
1−X.Y
2−----
3−
4−Initial release
servant-jsaddle/LICENSEdeleted−30
@@ -1,30 +0,0 @@
1−Copyright (c) 2014-2016, Zalora South East Asia Pte Ltd, Servant Contributors
2−
3−All rights reserved.
4−
5−Redistribution and use in source and binary forms, with or without
6−modification, are permitted provided that the following conditions are met:
7−
8− * Redistributions of source code must retain the above copyright
9− notice, this list of conditions and the following disclaimer.
10−
11− * Redistributions in binary form must reproduce the above
12− copyright notice, this list of conditions and the following
13− disclaimer in the documentation and/or other materials provided
14− with the distribution.
15−
16− * Neither the name of Zalora South East Asia Pte Ltd nor the names of other
17− contributors may be used to endorse or promote products derived
18− from this software without specific prior written permission.
19−
20−THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
21−"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
22−LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
23−A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
24−OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
25−SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
26−LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
27−DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
28−THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
29−(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
30−OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
servant-jsaddle/README.mddeleted−15
@@ -1,15 +0,0 @@
1−# `servant-client-jsaddle`
2−
3−This is a an implementation of the `servant-client-core` API on top of `jsaddle`, a framework that lets you write Haskell programs that compile to javascript to run in a browser or compile to native code that connects to a browser.
4−
5−It is similar to `servant-client-ghcjs`, except it supports native compilation and native GHCi. It even reuses some of the logic from `servant-client-ghcjs`.
6−
7−# Build
8−
9−This package comes with a test suite that depends on `jsaddle-webkit2gtk`. You may want to skip that because of the heavy dependency footprint.
10−
11− cabal new-build --allow-newer=aeson,http-types --disable-tests
12−
13−# Usage
14−
15−TBD. Similar to `servant-client` and `servant-client-ghcjs`.
servant-jsaddle/Setup.hsdeleted−2
@@ -1,2 +0,0 @@
1−import Distribution.Simple
2−main = defaultMain
servant-jsaddle/servant-jsaddle.cabaldeleted−125
@@ -1,125 +0,0 @@
1−name: servant-jsaddle
2−version: 0.16
3−synopsis:
4− automatic derivation of querying functions for servant webservices for jsaddle
5−
6−description:
7− This library lets you automatically derive Haskell functions that
8− let you query each endpoint of a <http://hackage.haskell.org/package/servant servant> webservice.
9− .
10− See <http://haskell-servant.readthedocs.org/en/stable/tutorial/Client.html the client section of the tutorial>.
11− .
12− <https://github.com/haskell-servant/servant/blob/master/servant-client/CHANGELOG.md CHANGELOG>
13−
14−license: BSD3
15−license-file: LICENSE
16−author: Servant Contributors
17−maintainer: haskell-servant-maintainers@googlegroups.com
18−copyright:
19− 2014-2016 Zalora South East Asia Pte Ltd, 2016-2017 Servant Contributors
20−
21−category: Servant, Web
22−build-type: Simple
23−cabal-version: >=1.10
24−tested-with:
25− GHC ==8.0.2 || ==8.2.2 || ==8.4.4 || ==8.6.5 || ==8.8.1
26− , GHCJS ==8.4
27−
28−homepage: http://haskell-servant.readthedocs.org/
29−bug-reports: http://github.com/haskell-servant/servant/issues
30−extra-source-files:
31− CHANGELOG.md
32− README.md
33−
34−source-repository head
35− type: git
36− location: http://github.com/haskell-servant/servant.git
37−
38−library
39− default-language: Haskell2010
40− hs-source-dirs: src
41− ghc-options: -Wall
42− exposed-modules:
43− Servant.Client.Internal.JSaddleXhrClient
44− Servant.Client.JSaddle
45−
46− -- Bundled with GHC: Lower bound to not force re-installs
47− -- text and mtl are bundled starting with GHC-8.4
48− build-depends:
49− base >=4.9 && <4.14
50− , bytestring >=0.10.8.1 && <0.11
51− , containers >=0.5.7.1 && <0.7
52− , mtl >=2.2.2 && <2.3
53− , text >=1.2.3.0 && <1.3
54− , transformers >=0.5.2.0 && <0.6
55−
56− if impl(ghcjs -any)
57− build-depends: ghcjs-base
58−
59− -- Servant dependencies.
60− -- Strict dependency on `servant-client-core` as we re-export things.
61− build-depends: servant-client-core >=0.16 && <0.16.1
62− build-depends:
63− base-compat >=0.10.5 && <0.12
64− , case-insensitive >=1.2.0.0 && <1.3
65− , exceptions >=0.10.0 && <0.11
66− , ghcjs-dom >=0.9.4.0 && <0.10
67− , http-media >=0.7.1.3 && <0.9
68− , http-types >=0.12.2 && <0.13
69− , jsaddle >=0.9.6.0 && <0.10
70− , monad-control >=1.0.2.3 && <1.1
71− , semigroupoids >=5.3.1 && <5.4
72− , string-conversions >=0.3 && <0.5
73− , transformers-base >=0.4.4 && <0.5
74−
75− if impl(ghc >=8.0)
76− ghc-options: -Wno-redundant-constraints
77−
78−test-suite spec
79− type: exitcode-stdio-1.0
80− ghc-options: -Wall
81− default-language: Haskell2010
82− hs-source-dirs: test
83− main-is: Spec.hs
84−
85− if impl(ghcjs -any)
86− build-depends:
87− base
88− , servant-jsaddle
89−
90− else
91− other-modules: Servant.Client.JSaddleSpec
92−
93− -- Dependencies inherited from the library. No need to specify bounds.
94− build-depends:
95− base
96− , bytestring
97− , containers
98− , exceptions
99− , ghcjs-dom
100− , http-media
101− , http-types
102− , jsaddle
103− , mtl
104− , process
105− , semigroupoids
106− , servant
107− , servant-client-core
108− , servant-jsaddle
109− , servant-server
110− , string-conversions
111− , text
112− , wai
113− , wai-cors
114− , wai-extra
115− , warp
116− , websockets
117−
118− -- Additonal dependencies
119− build-depends:
120− aeson
121− , hspec
122− , jsaddle-warp
123− , QuickCheck
124−
125− build-tool-depends: hspec-discover:hspec-discover >=2.6.0 && <2.8
servant-jsaddle/src/Servant/Client/Internal/JSaddleXhrClient.hsdeleted−311
@@ -1,311 +0,0 @@
1−{-# LANGUAGE CPP #-}
2−{-# LANGUAGE DeriveGeneric #-}
3−{-# LANGUAGE FlexibleContexts #-}
4−{-# LANGUAGE FlexibleInstances #-}
5−{-# LANGUAGE GeneralizedNewtypeDeriving #-}
6−{-# LANGUAGE MultiParamTypeClasses #-}
7−{-# LANGUAGE OverloadedStrings #-}
8−{-# LANGUAGE ScopedTypeVariables #-}
9−{-# LANGUAGE StandaloneDeriving #-}
10−{-# LANGUAGE TypeFamilies #-}
11−{-# LANGUAGE UndecidableInstances #-}
12−{-# LANGUAGE ViewPatterns #-}
13−{-# OPTIONS_GHC -fno-warn-name-shadowing #-}
14−
15−module Servant.Client.Internal.JSaddleXhrClient where
16−
17−import Prelude ()
18−import Prelude.Compat
19−
20−import Control.Concurrent
21− (MVar, newEmptyMVar, takeMVar, tryPutMVar)
22−import Control.Exception
23− (Exception, toException)
24−import Control.Monad
25− (forM_, unless, void)
26−import Control.Monad.Catch
27− (MonadCatch, MonadThrow, catch)
28−import Control.Monad.Error.Class
29− (MonadError (..))
30−import Control.Monad.IO.Class
31− (MonadIO (..))
32−import Control.Monad.Reader
33− (MonadReader, ReaderT, asks, runReaderT)
34−import Control.Monad.Trans.Except
35− (ExceptT, runExceptT)
36−import Data.Bifunctor
37− (bimap, first, second)
38−import Data.ByteString.Builder
39− (toLazyByteString)
40−import qualified Data.ByteString.Char8 as BS
41−import qualified Data.ByteString.Lazy as BSL
42−import qualified Data.ByteString.Lazy as L
43−import Data.CaseInsensitive
44− (mk, original)
45−import Data.Char
46− (isSpace)
47−import Data.Foldable
48− (toList)
49−import Data.Functor.Alt
50− (Alt (..))
51−import Data.Proxy
52− (Proxy (..))
53−import qualified Data.Sequence as Seq
54−import Data.String.Conversions
55− (cs)
56−import qualified Data.Text.Encoding as T
57−import qualified Data.Text.Encoding.Error as T
58−import GHC.Generics
59−import qualified GHCJS.Buffer as Buffer
60−import qualified GHCJS.DOM
61−import qualified GHCJS.DOM.EventM as JSDOM
62−import qualified GHCJS.DOM.Location as Location
63−import GHCJS.DOM.Types
64− (DOM, DOMContext, askDOM, runDOM)
65−import qualified GHCJS.DOM.Types as JS
66−import qualified GHCJS.DOM.Window as Window
67−import qualified GHCJS.DOM.XMLHttpRequest as JS
68−import qualified JavaScript.TypedArray.ArrayBuffer as ArrayBuffer
69−import qualified Language.Javascript.JSaddle.Types as JSaddle
70−import Network.HTTP.Media
71− (renderHeader)
72−import Network.HTTP.Types
73− (ResponseHeaders, http11, mkStatus, renderQuery, statusCode)
74−import System.IO
75− (hPutStrLn, stderr)
76−
77−import Servant.Client.Core
78−
79−-- Note: assuming encoding UTF-8
80−
81−data ClientEnv
82− = ClientEnv
83− { baseUrl :: BaseUrl
84− -- | Modify the XMLHttpRequest at will, right before sending.
85− , fixUpXhr :: JS.XMLHttpRequest -> DOM ()
86− }
87−
88−data JSaddleConnectionError = JSaddleConnectionError
89− deriving (Eq, Show)
90−
91−instance Exception JSaddleConnectionError
92−
93−-- | Default 'ClientEnv'
94−mkClientEnv :: BaseUrl -> ClientEnv
95−mkClientEnv burl = ClientEnv burl (const (pure ()))
96−
97−instance Show ClientEnv where
98− showsPrec prec (ClientEnv burl _) =
99− showParen (prec >= 11)
100− ( showString "ClientEnv {"
101− . showString "baseUrl = "
102− . showsPrec 0 burl
103− . showString ", fixUpXhr = <function>"
104− . showString "}"
105− )
106−
107−client :: HasClient ClientM api => Proxy api -> Client ClientM api
108−client api = api `clientIn` (Proxy :: Proxy ClientM)
109−
110−newtype ClientM a = ClientM
111− { fromClientM :: ReaderT ClientEnv (ExceptT ClientError DOM) a }
112− deriving ( Functor, Applicative, Monad, MonadIO, Generic
113− , MonadReader ClientEnv, MonadError ClientError)
114−deriving instance MonadThrow DOM => MonadThrow ClientM
115−deriving instance MonadCatch DOM => MonadCatch ClientM
116−
117−-- | Try clients in order, last error is preserved.
118−instance Alt ClientM where
119− a <!> b = a `catchError` const b
120−
121−instance RunClient ClientM where
122− throwClientError = throwError
123− runRequest r = do
124− d <- ClientM askDOM
125− performRequest d r
126−
127−runClientM :: ClientM a -> ClientEnv -> DOM (Either ClientError a)
128−runClientM cm env = runExceptT $ flip runReaderT env $ fromClientM cm
129−
130−runClientM' :: ClientM a -> DOM (Either ClientError a)
131−runClientM' m = do
132− burl <- getDefaultBaseUrl
133− runClientM m (mkClientEnv burl)
134−
135−getDefaultBaseUrl :: DOM BaseUrl
136−getDefaultBaseUrl = do
137− win <- GHCJS.DOM.currentWindow >>= \mw -> case mw of
138− Just x -> pure x
139− Nothing -> fail "Can not determine default base url without window."
140− curLoc <- Window.getLocation win
141−
142− protocolStr <- Location.getProtocol curLoc
143− portStr <- Location.getPort curLoc
144− hostname <- Location.getHostname curLoc
145−
146− let protocol
147− | (protocolStr :: JS.JSString) == "https:"
148− = Https
149− | otherwise = Http
150−
151− port :: Int
152− port | null portStr = case protocol of
153− Http -> 80
154− Https -> 443
155− | otherwise = read portStr
156−
157− pure (BaseUrl protocol hostname port "")
158−
159−performRequest :: DOMContext -> Request -> ClientM Response
160−performRequest domc req = do
161− xhr <- JS.newXMLHttpRequest `runDOM` domc
162− burl <- asks baseUrl
163− fixUp <- asks fixUpXhr
164− performXhr xhr burl req fixUp `runDOM` domc
165− resp <- toResponse domc xhr
166−
167− let status = statusCode (responseStatusCode resp)
168− unless (status >= 200 && status < 300) $
169− throwError $ mkFailureResponse burl req resp
170−
171− pure resp
172−
173−
174−-- * performing requests
175−-- Performs the xhr and blocks until the response was received
176−performXhr :: JS.XMLHttpRequest -> BaseUrl -> Request -> (JS.XMLHttpRequest -> DOM ()) -> DOM ()
177−performXhr xhr burl request fixUp = do
178−
179− let username, password :: Maybe JS.JSString
180− username = Nothing; password = Nothing
181−
182− JS.open xhr (decodeUtf8Lenient $ requestMethod request) (toUrl burl request) True username password
183− setHeaders xhr request
184− fixUp xhr
185−
186− waiter <- liftIO $ newEmptyMVar
187−
188− cleanup <- JSDOM.on xhr JS.readyStateChange $ do
189− state <- JS.getReadyState xhr
190− case state of
191− -- onReadyStateChange's callback can fire state 4
192− -- (which means "request finished and response is ready")
193− -- multiple times. By using tryPutMVar, only the first time
194− -- state 4 is fired will cause an MVar to be put. Subsequent
195− -- fires are ignored.
196− 4 -> void $ liftIO $ tryPutMVar waiter ()
197− _ -> return ()
198−
199− sendXhr xhr (toBody request) `catch` handleXHRError waiter -- We handle any errors in `toResponse`.
200−
201− liftIO $ takeMVar waiter
202−
203− cleanup
204−
205− where
206−
207− handleXHRError :: MVar () -> JS.XHRError -> DOM ()
208− handleXHRError waiter e = do
209− liftIO $ hPutStrLn stderr $ "servant-client-jsaddle: exception in `sendXhr` (should get handled in response handling): " <> show e
210− void $ liftIO $ tryPutMVar waiter ()
211−
212−
213−toUrl :: BaseUrl -> Request -> JS.JSString
214−toUrl burl request =
215− let pathS = JS.toJSString $ decodeUtf8Lenient $ L.toStrict $ toLazyByteString $
216− requestPath request
217− queryS =
218− JS.toJSString $ decodeUtf8Lenient $
219− renderQuery True $
220− toList $
221− requestQueryString request
222− in JS.toJSString (showBaseUrl burl) <> pathS <> queryS :: JS.JSString
223−
224−setHeaders :: JS.XMLHttpRequest -> Request -> DOM ()
225−setHeaders xhr request = do
226− forM_ (toList $ requestAccept request) $ \mediaType -> -- FIXME review
227− JS.setRequestHeader
228− xhr
229− ("Accept" :: JS.JSString)
230− (decodeUtf8Lenient $ renderHeader mediaType)
231−
232− forM_ (requestBody request) $ \(_, mediaType) ->
233− JS.setRequestHeader
234− xhr
235− ("Content-Type" :: JS.JSString)
236− (decodeUtf8Lenient $ renderHeader mediaType)
237−
238− forM_ (toList $ requestHeaders request) $ \(key, value) ->
239− JS.setRequestHeader xhr (decodeUtf8Lenient $ original key) (decodeUtf8Lenient value)
240−
241−-- ArrayBufferView is a type that only exists in the spec and covers many concrete types.
242−castMutableArrayBufferToArrayBufferView :: ArrayBuffer.MutableArrayBuffer -> DOM JS.ArrayBufferView
243−castMutableArrayBufferToArrayBufferView x = JS.liftJSM $ do
244− JS.fromJSValUnchecked $ JS.pToJSVal x
245−
246−mkFailureResponse :: BaseUrl -> Request -> ResponseF BSL.ByteString -> ClientError
247−mkFailureResponse burl request =
248− FailureResponse (bimap (const ()) f request)
249− where
250− f b = (burl, BSL.toStrict $ toLazyByteString b)
251−
252−sendXhr :: JS.XMLHttpRequest -> Maybe L.ByteString -> DOM ()
253−sendXhr xhr Nothing = JS.send xhr
254−sendXhr xhr (Just body) = do
255− -- Reason for copy: hopefully offset will be 0 and length b == len
256− -- FIXME: use a typed array constructor that accepts offset and length and skip the copy
257− (b, _offset, _len) <- JSaddle.ghcjsPure $ Buffer.fromByteString $ BS.copy $ L.toStrict body
258− b' <- Buffer.thaw b
259− b'' <- JSaddle.ghcjsPure $ Buffer.getArrayBuffer b'
260− JS.sendArrayBuffer xhr =<< castMutableArrayBufferToArrayBufferView b''
261−
262−toBody :: Request -> Maybe L.ByteString
263−toBody request = case requestBody request of
264− Nothing -> Nothing
265− Just (RequestBodyLBS "", _) -> Nothing
266− Just (RequestBodyLBS x, _) -> Just x
267− Just (RequestBodyBS "", _) -> Nothing
268− Just (RequestBodyBS x, _) -> Just $ L.fromStrict x
269− Just (RequestBodySource _, _) -> error "RequestBodySource isn't supported"
270−
271−-- * inspecting the xhr response
272−
273−-- This function is only supposed to handle 'ConnectionError's. Other
274−-- 'ClientError's are created in Servant.Client.Req.
275−toResponse :: DOMContext -> JS.XMLHttpRequest -> ClientM Response
276−toResponse domc xhr = do
277− let inDom :: DOM a -> ClientM a
278− inDom = flip runDOM domc
279− status <- inDom $ JS.getStatus xhr
280− case status of
281− 0 -> throwError $ ConnectionError $ toException JSaddleConnectionError
282− _ -> inDom $ do
283− statusText <- BS.pack <$> JS.getStatusText xhr
284− headers <- parseHeaders <$> JS.getAllResponseHeaders xhr
285− responseText <- maybe "" (L.fromStrict . BS.pack) <$> JS.getResponseText xhr -- FIXME: Text/Binary? Performance? Test?
286− pure Response
287− { responseStatusCode = mkStatus (fromIntegral status) statusText
288− , responseBody = responseText
289− , responseHeaders = Seq.fromList headers
290− , responseHttpVersion = http11 -- this is made up
291− }
292−
293−parseHeaders :: String -> ResponseHeaders
294−parseHeaders s =
295− (first mk . first strip . second strip . parseHeader) <$>
296− splitOn "\r\n" (cs s)
297− where
298− parseHeader :: BS.ByteString -> (BS.ByteString, BS.ByteString)
299− parseHeader h = case BS.breakSubstring ":" (cs h) of
300− (key, BS.drop 1 -> value) -> (key, value)
301−
302− splitOn :: BS.ByteString -> BS.ByteString -> [BS.ByteString]
303− splitOn separator input = case BS.breakSubstring separator input of
304− (prefix, "") -> [prefix]
305− (prefix, rest) -> prefix : splitOn separator (BS.drop (BS.length separator) rest)
306−
307− strip :: BS.ByteString -> BS.ByteString
308− strip = BS.dropWhile isSpace . BS.reverse . BS.dropWhile isSpace . BS.reverse
309−
310−decodeUtf8Lenient :: BS.ByteString -> JS.JSString
311−decodeUtf8Lenient = JS.toJSString . T.decodeUtf8With T.lenientDecode
servant-jsaddle/src/Servant/Client/JSaddle.hsdeleted−20
@@ -1,20 +0,0 @@
1−-- | This module provides 'client' which can automatically generate
2−-- querying functions for each endpoint just from the type representing your
3−-- API.
4−module Servant.Client.JSaddle
5− (
6− client
7− , ClientM
8− , runClientM
9− , runClientM'
10−
11− -- * Configuration
12− , ClientEnv(..)
13− , mkClientEnv
14− , getDefaultBaseUrl
15−
16− , module Servant.Client.Core.Reexport
17− ) where
18−
19−import Servant.Client.Internal.JSaddleXhrClient
20−import Servant.Client.Core.Reexport
servant-jsaddle/test/Servant/Client/JSaddleSpec.hsdeleted−173
@@ -1,173 +0,0 @@
1−{-# LANGUAGE DataKinds #-}
2−{-# LANGUAGE DeriveAnyClass #-}
3−{-# LANGUAGE DeriveGeneric #-}
4−{-# LANGUAGE OverloadedStrings #-}
5−{-# LANGUAGE TypeApplications #-}
6−{-# LANGUAGE TypeOperators #-}
7−module Servant.Client.JSaddleSpec where
8−
9−import Control.Concurrent
10− (threadDelay)
11−import Control.Concurrent.MVar
12− (newEmptyMVar, putMVar, takeMVar)
13−import Control.Exception
14− (handle, throwIO)
15−import Control.Monad.Trans
16−import Data.Aeson
17−import Data.ByteString
18− (ByteString)
19−import qualified Data.ByteString as B
20−import Data.Proxy
21−import Data.String
22−import Data.Word
23−import GHC.Generics
24−import qualified GHCJS.DOM
25−import qualified GHCJS.DOM.Window as Window
26−import Language.Javascript.JSaddle.Monad
27− (JSM)
28−import qualified Language.Javascript.JSaddle.Monad as JSaddle
29−import qualified Language.Javascript.JSaddle.Run as Run
30−import qualified Language.Javascript.JSaddle.WebSockets as WS
31−import qualified Network.HTTP.Types as Http
32−import qualified Network.Wai as Wai
33−import Network.Wai.Handler.Warp as Warp
34−import Network.Wai.Middleware.AddHeaders
35−import Network.Wai.Middleware.Cors
36− (simpleCors)
37−import Network.WebSockets
38− (defaultConnectionOptions)
39−import qualified Network.WebSockets as WS
40−import Servant.API
41−import Servant.Client.JSaddle
42−import Servant.Server
43−import qualified System.Process as P
44−import Test.Hspec
45−
46−type TestApi = ReqBody '[OctetStream] ByteString :> Post '[JSON] TestResponse
47−testApi :: Proxy TestApi
48−testApi = Proxy
49−
50−data TestResponse = TestResponse { byteList :: [Word8] }
51− deriving (Generic, ToJSON, FromJSON, Show, Eq)
52−
53−testServer :: Server TestApi
54−testServer x = do
55− pure . TestResponse . B.unpack $ x
56−
57−testClient :: Client ClientM TestApi
58−testClient = client testApi
59−
60−-- WARNING: approximation!
61−jsaddleFinally :: JSM b -> JSM a -> JSM a
62−jsaddleFinally handler m = JSaddle.bracket (pure ()) (const handler) (const m)
63−-- jsaddleFinally handler m = JSaddle.catch (m <* handler) (\e -> handler >> throw (e :: SomeException))
64−
65−close :: JSM ()
66−close = do
67− mw <- GHCJS.DOM.currentWindow
68− case mw of
69− Just w -> do
70− liftIO $ putStrLn "Closing window..."
71− Window.close w
72− Nothing -> liftIO $ putStrLn "Can't close the window!"
73−
74−
75−
76−spec :: Spec
77−spec = do
78− describe "Servant.Client.JSaddle" $ do
79− it "Receive a properly encoded response" $ do
80− -- A mvar to tell promptly when we are done
81− done <- newEmptyMVar
82−
83− -- How this work:
84− --
85− -- 1. we start server warp, which serves simple API
86− -- 2. we start client warp, which serves jsaddle running the 'action'
87− -- 3. we run google-chrome-stable to open jsaddle page and to run the test
88−
89− let action :: Int -> JSM ()
90− action serverPort = do
91− liftIO $ threadDelay $ 500 * 1000
92− -- a mix of valid utf-8 and non-utf8 bytes
93− let bytes = [0x01, 0xff, 0x02, 0xfe, 0x03, 0xfd, 0x00, 0x64, 0xc3, 0xbb, 0x68, 0xc3]
94− response <- flip runClientM clientEnv $ testClient (B.pack bytes)
95− liftIO $ print response
96− liftIO $ response `shouldBe` Right (TestResponse bytes)
97−
98− -- we are done.
99− liftIO $ putMVar done ()
100− where
101− clientEnv = mkClientEnv BaseUrl
102− { baseUrlScheme = Http
103− , baseUrlHost = "localhost"
104− , baseUrlPort = fromIntegral serverPort
105− , baseUrlPath = "/"
106− }
107−
108− let serverApp :: IO Application
109− serverApp = pure $ logRequest $ addCors $ serve testApi testServer
110−
111− let handler :: WS.ConnectionException -> IO ()
112− handler WS.ConnectionClosed = return ()
113− handler e = throwIO e
114−
115− handle handler $ Warp.testWithApplication serverApp $ \serverPort -> do
116− threadDelay $ 500 * 1000
117−
118− let clientApp :: IO Application
119− clientApp = WS.jsaddleOr defaultConnectionOptions (action serverPort >> Run.syncPoint) WS.jsaddleApp
120−
121− Warp.testWithApplication (simpleCors <$> clientApp) $ \clientPort -> do
122− threadDelay $ 500 * 1000
123−
124− putStrLn $ "server http://localhost:" ++ show serverPort
125− putStrLn $ "client http://localhost:" ++ show clientPort
126− putStrLn $ "google-chrome-stable --headless --disable-gpu --screenshot http://localhost:" ++ show clientPort
127−
128−
129− -- Run headless chrome
130− -- https://docs.travis-ci.com/user/gui-and-headless-browsers/#using-the-chrome-addon-in-the-headless-mode
131− -- https://developers.google.com/web/updates/2017/04/headless-chrome
132− hdl <- P.spawnProcess "google-chrome-stable"
133− [ "--headless"
134− , "--disable-gpu"
135− , "--remote-debugging-port=9222" -- TODO: bind to random port
136− , "http://localhost:" ++ show clientPort
137− ]
138−
139− -- wait for test to run.
140− takeMVar done
141−
142− -- kill chrome
143− P.terminateProcess hdl
144−
145−-------------------------------------------------------------------------------
146−-- Logger middleware
147−-------------------------------------------------------------------------------
148−
149−logRequest :: Wai.Middleware
150−logRequest app request respond = do
151− putStrLn "Request"
152− print request
153− app request $ \response -> do
154− putStrLn "Response Headers"
155− mapM_ print (Wai.responseHeaders response)
156− respond response
157−
158−-------------------------------------------------------------------------------
159−-- OPTIONS
160−-------------------------------------------------------------------------------
161−
162−corsHeaders :: (IsString s1, IsString s2) => [(s1, s2)]
163−corsHeaders =
164− [ ("Access-Control-Allow-Origin", "*")
165− , ("Access-Control-Allow-Methods", "POST")
166− , ("Access-Control-Allow-Headers", "content-type")
167− ]
168−
169−addCors :: Wai.Middleware
170−addCors app request respond =
171− if Wai.requestMethod request == "OPTIONS"
172− then respond $ Wai.responseLBS Http.status200 corsHeaders ""
173− else addHeaders corsHeaders app request respond
servant-jsaddle/test/Spec.hsdeleted−8
@@ -1,8 +0,0 @@
1−{-# LANGUAGE CPP #-}
2−#ifdef __GHCJS__
3−module Main (main) where
4−main :: IO ()
5−main = return ()
6−#else
7−{-# OPTIONS_GHC -F -pgmF hspec-discover #-}
8−#endif