on master help sign in
json serialization compiles
commitaa45cffb5e0459fab4efd7a607d42baf126d62b9 authorAgentM <agentm@themactionfaction.com> dateSat 23 Jul 2016, 23:28 (10 years ago) parentb0525ca
4 files changed+136−4
ProjectM36/ConcreteTypeRep.hs+4−3 ProjectM36/Server/RemoteCallTypes/Json.hs+107 ProjectM36/Server/WebSocket.hs+24 project-m36.cabal+1−1
ProjectM36/ConcreteTypeRep.hs+4−3
@@ -1,14 +1,15 @@
1−{-# LANGUAGE GeneralizedNewtypeDeriving #-}
1+{-# LANGUAGE GeneralizedNewtypeDeriving, DeriveGeneric #-}
22-- adapted from https://hackage.haskell.org/package/concrete-typerep
33module ProjectM36.ConcreteTypeRep where
44import Data.Binary
55import Data.Typeable
66import Data.Typeable.Internal
77import Control.DeepSeq (NFData)
8+import GHC.Generics
89
910newtype ConcreteTypeRep = CTR { unCTR :: TypeRep } deriving (Eq, Typeable, NFData)
1011
11−newtype SerialRep = SR (TyConRep, [SerialRep]) deriving (Binary)
12+newtype SerialRep = SR (TyConRep, [SerialRep]) deriving (Binary, Generic)
1213
1314instance Show ConcreteTypeRep where
1415 show (CTR tRep) = show tRep
@@ -17,8 +18,8 @@ type TyConRep = (String, String, String)
1718toTyConRep :: TyCon -> TyConRep
1819toTyConRep (TyCon _ pack modul name) = (pack, modul, name)
1920
20−fromTyConRep (pack, modul, name) = mkTyCon3 pack modul name
2121fromTyConRep :: TyConRep -> TyCon
22+fromTyConRep (pack, modul, name) = mkTyCon3 pack modul name
2223
2324toSerial :: ConcreteTypeRep -> SerialRep
2425toSerial (CTR t) = case splitTyConApp t of
ProjectM36/Server/RemoteCallTypes/Json.hsnew file+107
@@ -0,0 +1,107 @@
1+--create a bunch of orphan instances for use with the websocket server
2+{-# LANGUAGE OverloadedStrings #-}
3+{-# OPTIONS_GHC -fno-warn-orphans #-}
4+module ProjectM36.Server.RemoteCallTypes.Json where
5+import ProjectM36.Server.RemoteCallTypes
6+import ProjectM36.Base
7+import ProjectM36.ConcreteTypeRep
8+import Data.Aeson
9+import Data.UUID.Aeson ()
10+import Data.Proxy
11+import Data.Typeable
12+import Data.Text
13+import Data.Time.Calendar
14+import ProjectM36.Atom
15+import Data.ByteString
16+
17+instance ToJSON RelationalExpr
18+instance FromJSON RelationalExpr
19+
20+instance ToJSON TupleExpr
21+instance FromJSON TupleExpr
22+
23+instance ToJSON RestrictionPredicateExpr
24+instance FromJSON RestrictionPredicateExpr
25+
26+instance ToJSON AtomExpr
27+instance FromJSON AtomExpr
28+
29+instance ToJSON RelationTupleSet
30+instance FromJSON RelationTupleSet
31+
32+instance ToJSON RelationTuple
33+instance FromJSON RelationTuple
34+
35+instance ToJSON ExecuteRelationalExpr
36+instance FromJSON ExecuteRelationalExpr
37+
38+instance ToJSON Relation
39+instance FromJSON Relation
40+
41+instance ToJSON Attribute
42+instance FromJSON Attribute
43+
44+instance ToJSON ExtendTupleExpr
45+instance FromJSON ExtendTupleExpr
46+
47+instance ToJSON AttributeNames
48+instance FromJSON AttributeNames
49+
50+instance ToJSON AttributeExpr
51+instance FromJSON AttributeExpr
52+
53+instance ToJSON AtomType
54+instance FromJSON AtomType
55+
56+instance ToJSON TypeConstructor
57+instance FromJSON TypeConstructor
58+
59+instance ToJSON TypeConstructorArg
60+instance FromJSON TypeConstructorArg
61+
62+instance ToJSON SerialRep
63+instance FromJSON SerialRep
64+
65+instance FromJSON ConcreteTypeRep where
66+ parseJSON = withObject "ctr" $ \o -> do
67+ serialRep <- o .: "serialrep"
68+ pure $ fromSerial serialRep
69+
70+instance ToJSON ConcreteTypeRep where
71+ toJSON ctr = object [
72+ "serialrep" .= toSerial ctr
73+ ]
74+
75+instance ToJSON Atom where
76+ toJSON atom@(Atom val) = object [
77+ "type" .= toJSON (atomTypeForAtom atom),
78+ "val" .= toText val]
79+ toJSON (ConstructedAtom dConsName atomtype atomlist) = object [
80+ "dataconstructorname" .= dConsName,
81+ "atomtype" .= toJSON atomtype,
82+ "atomlist" .= toJSON atomlist
83+ ]
84+
85+instance FromJSON Atom where
86+ parseJSON = withObject "atom" $ \o -> do
87+ atype <- o .: "type"
88+ case atype of
89+ AnyAtomType -> fail "cannot pass AnyAtomType over the wire"
90+ caType@(ConstructedAtomType _ _) -> ConstructedAtom <$> o .: "dataconstructorname" <*> pure caType <*> o .: "atom"
91+ RelationAtomType _ -> undefined
92+ AtomType cTypeRep -> if unCTR cTypeRep == typeRep (Proxy :: Proxy Int) then
93+ intAtom <$> o .: "val"
94+ else if unCTR cTypeRep == typeRep (Proxy :: Proxy Text) then
95+ textAtom <$> o .: "val"
96+ else if unCTR cTypeRep == typeRep (Proxy :: Proxy Double) then
97+ textAtom <$> o .: "val"
98+ else if unCTR cTypeRep == typeRep (Proxy :: Proxy Day) then
99+ undefined
100+ else if unCTR cTypeRep == typeRep (Proxy :: Proxy ByteString) then
101+ undefined
102+ else if unCTR cTypeRep == typeRep (Proxy :: Proxy Bool) then
103+ undefined
104+ else
105+ error "unsupported typerep serialization"
106+
107+
ProjectM36/Server/WebSocket.hsnew file+24
@@ -0,0 +1,24 @@
1+{-# LANGUAGE OverloadedStrings #-}
2+--module ProjectM36.Server.WebSocket where
3+
4+import Control.Monad (forever)
5+import qualified Data.Text as T
6+import qualified Network.WebSockets as WS
7+import ProjectM36.Server.RemoteCallTypes.Json
8+
9+main :: IO ()
10+main = do
11+ --this built-in server is apparently not meant for production use, but it's easier to test than starting up the wai or snap interfaces
12+ WS.runServer "0.0.0.0" 8888 application
13+
14+application :: WS.ServerApp
15+application pending = do
16+ conn <- WS.acceptRequest pending
17+ forever $ do
18+ msg <- (WS.receiveData conn) :: IO T.Text
19+ case msg of
20+ "hello" -> WS.sendTextData conn ("nice" :: T.Text)
21+ "bye" -> WS.sendClose conn ("bye" :: T.Text)
22+ str -> WS.sendTextData conn str
23+ return ()
24+
project-m36.cabal+1−1
@@ -608,7 +608,7 @@ Test-Suite test-scripts
608608
609609Executable project-m36-websocket-server
610610 Default-Language: Haskell2010
611− Build-Depends: base, HUnit, Cabal, containers, hashable, unordered-containers, mtl, vector, vector-binary-instances, time, hashable-time, bytestring, network-transport-tcp, distributed-process, distributed-process-extras, distributed-process-client-server, uuid, stm, deepseq, deepseq-generics, binary, unix, parallel, cassava, attoparsec, gnuplot, directory, temporary, haskeline, parsec, text, base64-bytestring, data-interval, filepath, transformers, stm-containers, list-t, persistent, aeson, path-pieces, either, conduit, http-api-data, template-haskell, persistent-template, websockets, aeson
611+ Build-Depends: base, HUnit, Cabal, containers, hashable, unordered-containers, mtl, vector, vector-binary-instances, time, hashable-time, bytestring, network-transport-tcp, distributed-process, distributed-process-extras, distributed-process-client-server, uuid, stm, deepseq, deepseq-generics, binary, unix, parallel, cassava, attoparsec, gnuplot, directory, temporary, haskeline, parsec, text, base64-bytestring, data-interval, filepath, transformers, stm-containers, list-t, persistent, aeson, path-pieces, either, conduit, http-api-data, template-haskell, persistent-template, websockets, aeson, uuid-aeson
612612 Main-Is: ProjectM36/Server/WebSocket.hs
613613 GHC-Options: -Wall
614614 if os(windows)