Parsing JSON messages: FIXED.

master
Philippe Pittoli 2023-05-25 00:07:59 +02:00
parent 0671e1780c
commit 2d269d088c
3 changed files with 33 additions and 24 deletions

View File

@ -8,6 +8,7 @@ import Data.Array as A
import Data.Tuple (Tuple(..)) import Data.Tuple (Tuple(..))
import Data.Bifunctor (lmap) import Data.Bifunctor (lmap)
-- import Data.Codec.Argonaut (JsonCodec, JsonDecodeError) -- import Data.Codec.Argonaut (JsonCodec, JsonDecodeError)
import Data.Argonaut.Core as J
import Data.Codec.Argonaut as CA import Data.Codec.Argonaut as CA
import Data.Const (Const) import Data.Const (Const)
import Data.Either (Either(..)) import Data.Either (Either(..))
@ -334,9 +335,9 @@ handleAction = case _ of
-- Cases where we didn't understand the message. -- Cases where we didn't understand the message.
Left err -> do Left err -> do
case err of case err of
(AuthD.JSONERROR jerr) -> do (AuthD.JSONERROR jerr) -> do
print_json_string messageEvent.message print_json_string messageEvent.message
handleAction $ WebSocketParseError ("JSON parsing error:" <> (CA.printJsonDecodeError jerr)) handleAction $ WebSocketParseError ("JSON parsing error: " <> jerr <> " JSON is: " <> jerr)
(AuthD.UnknownError unerr) -> handleAction $ WebSocketParseError ("Parsing error: AuthD.UnknownError" <> (show unerr)) (AuthD.UnknownError unerr) -> handleAction $ WebSocketParseError ("Parsing error: AuthD.UnknownError" <> (show unerr))
(AuthD.UnknownNumber ) -> handleAction $ WebSocketParseError ("Parsing error: AuthD.UnknownNumber") (AuthD.UnknownNumber ) -> handleAction $ WebSocketParseError ("Parsing error: AuthD.UnknownNumber")
-- Cases where we understood the message. -- Cases where we understood the message.

View File

@ -18,7 +18,7 @@ import Prelude (bind, (<$>), discard, ($), (>>>), (+), (-))
import Effect (Effect) import Effect (Effect)
import Effect.Class (liftEffect) import Effect.Class (liftEffect)
import Data.UInt (fromInt, UInt) import Data.UInt (fromInt, toInt, UInt)
import Data.Tuple (Tuple(..)) import Data.Tuple (Tuple(..))
import Data.ArrayBuffer.ArrayBuffer as ArrayBuffer import Data.ArrayBuffer.ArrayBuffer as ArrayBuffer
import Data.ArrayBuffer.Types (ArrayBuffer, DataView) import Data.ArrayBuffer.Types (ArrayBuffer, DataView)
@ -78,8 +78,8 @@ fromIPC arrayBuffer = do
runParserT dataView do runParserT dataView do
-- First parse a 32-bit big-endian length prefix for the length -- First parse a 32-bit big-endian length prefix for the length
-- of the UTF-8 string in bytes. -- of the UTF-8 string in bytes.
length <- Parsing.DataView.anyInt32be length <- Parsing.DataView.anyUint32be
stringview <- Parsing.DataView.takeN length stringview <- Parsing.DataView.takeN (toInt length)
stringarray <- lift $ liftEffect $ Cast.toUint8Array stringview stringarray <- lift $ liftEffect $ Cast.toUint8Array stringview
hoistEffectParserT $ TextDecoder.decode stringarray textDecoder hoistEffectParserT $ TextDecoder.decode stringarray textDecoder
@ -93,10 +93,10 @@ fromTypedIPC arraybuffer = do
runParserT dataView do runParserT dataView do
-- First parse a 32-bit big-endian length prefix for the length -- First parse a 32-bit big-endian length prefix for the length
-- of the UTF-8 string in bytes. -- of the UTF-8 string in bytes.
length <- Parsing.DataView.anyInt32be length <- Parsing.DataView.anyUint32be
-- Second parse a 8-bit unsigned integer representing the type of -- Second parse a 8-bit unsigned integer representing the type of
-- the message to decode. -- the message to decode.
messageTypeNumber <- Parsing.DataView.anyUint8 messageTypeNumber <- Parsing.DataView.anyUint8
stringview <- Parsing.DataView.takeN (length - 1) stringview <- Parsing.DataView.takeN ((toInt length) - 1)
stringarray <- lift $ liftEffect $ Cast.toUint8Array stringview stringarray <- lift $ liftEffect $ Cast.toUint8Array stringview
hoistEffectParserT $ (Tuple messageTypeNumber) <$> TextDecoder.decode stringarray textDecoder hoistEffectParserT $ (Tuple messageTypeNumber) <$> TextDecoder.decode stringarray textDecoder

View File

@ -16,6 +16,8 @@ import Data.Tuple (Tuple(..))
import Data.ArrayBuffer.Types (ArrayBuffer) import Data.ArrayBuffer.Types (ArrayBuffer)
import Effect.Class (liftEffect) import Effect.Class (liftEffect)
import Data.Argonaut.Parser as JSONParser
import Data.Bifunctor (lmap)
import App.IPC as IPC import App.IPC as IPC
@ -58,7 +60,8 @@ import App.IPC as IPC
-} -}
-- Basic message types. -- Basic message types.
type Error = { reason :: Maybe String } -- type Error = { reason :: Maybe String }
type Error = { reason :: String }
type Token = { uid :: Int, token :: String } type Token = { uid :: Int, token :: String }
type Contacts = { user :: Int, email :: Maybe String, phone :: Maybe String } type Contacts = { user :: Int, email :: Maybe String, phone :: Maybe String }
@ -66,6 +69,18 @@ type Email = String
type Password = String type Password = String
type GetToken = { login :: String, password :: String } type GetToken = { login :: String, password :: String }
-- Related JSON codecs.
codecGetToken ∷ CA.JsonCodec GetToken
codecGetToken = CA.object "GetToken" (CAR.record { login: CA.string, password: CA.string })
codecGotError ∷ CA.JsonCodec Error
codecGotError = CA.object "Error" (CAR.record { reason: CA.string })
-- codecGotError = CA.object "Error" (CAR.record { reason: CAR.optional CA.string })
codecGotToken ∷ CA.JsonCodec Token
codecGotToken = CA.object "Token" (CAR.record { "uid": CA.int, "token": CA.string })
codecGotContacts ∷ CA.JsonCodec Contacts
codecGotContacts = CA.object "Contacts" (CAR.record { user: CA.int, email: CAR.optional CA.string, phone: CAR.optional CA.string })
-- All possible requests. -- All possible requests.
data RequestMessage data RequestMessage
= MkGetToken GetToken -- 0 = MkGetToken GetToken -- 0
@ -124,17 +139,13 @@ encode m = case m of
-- 17 Delete -- 17 Delete
-- 18 GetContacts -- 18 GetContacts
where
codecGetToken ∷ CA.JsonCodec GetToken
codecGetToken = CA.object "GetToken" (CAR.record { login: CA.string, password: CA.string })
data DecodeError data DecodeError
= JSONERROR CA.JsonDecodeError = JSONERROR String
| UnknownError String | UnknownError String
| UnknownNumber | UnknownNumber
decode :: Int -> J.Json -> Either DecodeError AnswerMessage decode :: Int -> String -> Either DecodeError AnswerMessage
decode number json decode number string
= case number of = case number of
0 -> error_management codecGotError GotError 0 -> error_management codecGotError GotError
1 -> error_management codecGotToken GotToken 1 -> error_management codecGotToken GotToken
@ -154,17 +165,14 @@ decode number json
-- Signature is required since the compiler's guess is wrong. -- Signature is required since the compiler's guess is wrong.
error_management :: forall a. CA.JsonCodec a -> (a -> AnswerMessage) -> Either DecodeError AnswerMessage error_management :: forall a. CA.JsonCodec a -> (a -> AnswerMessage) -> Either DecodeError AnswerMessage
error_management codec f error_management codec f
= case (CA.decode codec json) of = case (parseDecodeJSON codec string) of
(Left err) -> Left (JSONERROR err) (Left err) -> Left (JSONERROR err)
(Right v) -> Right (f v) (Right v) -> Right (f v)
-- Related JSON codecs. parseDecodeJSON :: forall a. CA.JsonCodec a -> String -> Either String a
codecGotError ∷ CA.JsonCodec Error parseDecodeJSON codec str = do
codecGotError = CA.object "Error" (CAR.record { "reason": CAR.optional CA.string }) json <- JSONParser.jsonParser str
codecGotToken ∷ CA.JsonCodec Token lmap CA.printJsonDecodeError (CA.decode codec json)
codecGotToken = CA.object "Token" (CAR.record { "uid": CA.int, "token": CA.string })
codecGotContacts ∷ CA.JsonCodec Contacts
codecGotContacts = CA.object "Contacts" (CAR.record { user: CA.int, email: CAR.optional CA.string, phone: CAR.optional CA.string })
serialize :: RequestMessage -> Effect ArrayBuffer serialize :: RequestMessage -> Effect ArrayBuffer
@ -178,6 +186,6 @@ deserialize arraybuffer
value <- liftEffect $ IPC.fromTypedIPC arraybuffer value <- liftEffect $ IPC.fromTypedIPC arraybuffer
pure $ case (value) of pure $ case (value) of
Left err -> Left (UnknownError $ show err) Left err -> Left (UnknownError $ show err)
Right (Tuple messageTypeNumber string) -> case (decode (toInt messageTypeNumber) $ J.fromString string) of Right (Tuple messageTypeNumber string) -> case (decode (toInt messageTypeNumber) string) of
Left parsingError -> Left parsingError Left parsingError -> Left parsingError
Right answerMessage -> Right answerMessage Right answerMessage -> Right answerMessage