diff --git a/apps/ios/SimpleX.xcodeproj/project.pbxproj b/apps/ios/SimpleX.xcodeproj/project.pbxproj index 7ff35241c..9ccab2ff6 100644 --- a/apps/ios/SimpleX.xcodeproj/project.pbxproj +++ b/apps/ios/SimpleX.xcodeproj/project.pbxproj @@ -7,14 +7,16 @@ objects = { /* Begin PBXBuildFile section */ - 5C764E61279C70E0000C6508 /* libgmp.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 5C764E5D279C70DE000C6508 /* libgmp.a */; }; - 5C764E62279C70E0000C6508 /* libgmp.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 5C764E5D279C70DE000C6508 /* libgmp.a */; }; - 5C764E63279C70E0000C6508 /* libgmpxx.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 5C764E5E279C70DE000C6508 /* libgmpxx.a */; }; - 5C764E64279C70E0000C6508 /* libgmpxx.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 5C764E5E279C70DE000C6508 /* libgmpxx.a */; }; - 5C764E65279C70E0000C6508 /* libffi.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 5C764E5F279C70DE000C6508 /* libffi.a */; }; - 5C764E66279C70E0000C6508 /* libffi.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 5C764E5F279C70DE000C6508 /* libffi.a */; }; - 5C764E67279C70E0000C6508 /* libHSsimplex-chat-1.0.1-756RvUPisyT7gsYObFpxWS-ghc8.10.7.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 5C764E60279C70E0000C6508 /* libHSsimplex-chat-1.0.1-756RvUPisyT7gsYObFpxWS-ghc8.10.7.a */; }; - 5C764E68279C70E0000C6508 /* libHSsimplex-chat-1.0.1-756RvUPisyT7gsYObFpxWS-ghc8.10.7.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 5C764E60279C70E0000C6508 /* libHSsimplex-chat-1.0.1-756RvUPisyT7gsYObFpxWS-ghc8.10.7.a */; }; + 5C1AEB82279F4A6400247F08 /* libHSsimplex-chat-1.0.2-FYXW0143sf06WiRQx9DgCD.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 5C1AEB7D279F4A6400247F08 /* libHSsimplex-chat-1.0.2-FYXW0143sf06WiRQx9DgCD.a */; }; + 5C1AEB83279F4A6400247F08 /* libHSsimplex-chat-1.0.2-FYXW0143sf06WiRQx9DgCD.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 5C1AEB7D279F4A6400247F08 /* libHSsimplex-chat-1.0.2-FYXW0143sf06WiRQx9DgCD.a */; }; + 5C1AEB84279F4A6400247F08 /* libHSsimplex-chat-1.0.2-FYXW0143sf06WiRQx9DgCD-ghc8.10.7.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 5C1AEB7E279F4A6400247F08 /* libHSsimplex-chat-1.0.2-FYXW0143sf06WiRQx9DgCD-ghc8.10.7.a */; }; + 5C1AEB85279F4A6400247F08 /* libHSsimplex-chat-1.0.2-FYXW0143sf06WiRQx9DgCD-ghc8.10.7.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 5C1AEB7E279F4A6400247F08 /* libHSsimplex-chat-1.0.2-FYXW0143sf06WiRQx9DgCD-ghc8.10.7.a */; }; + 5C1AEB86279F4A6400247F08 /* libffi.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 5C1AEB7F279F4A6400247F08 /* libffi.a */; }; + 5C1AEB87279F4A6400247F08 /* libffi.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 5C1AEB7F279F4A6400247F08 /* libffi.a */; }; + 5C1AEB88279F4A6400247F08 /* libgmp.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 5C1AEB80279F4A6400247F08 /* libgmp.a */; }; + 5C1AEB89279F4A6400247F08 /* libgmp.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 5C1AEB80279F4A6400247F08 /* libgmp.a */; }; + 5C1AEB8A279F4A6400247F08 /* libgmpxx.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 5C1AEB81279F4A6400247F08 /* libgmpxx.a */; }; + 5C1AEB8B279F4A6400247F08 /* libgmpxx.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 5C1AEB81279F4A6400247F08 /* libgmpxx.a */; }; 5C764E80279C7276000C6508 /* dummy.m in Sources */ = {isa = PBXBuildFile; fileRef = 5C764E7F279C7276000C6508 /* dummy.m */; }; 5C764E81279C7276000C6508 /* dummy.m in Sources */ = {isa = PBXBuildFile; fileRef = 5C764E7F279C7276000C6508 /* dummy.m */; }; 5C764E82279C748B000C6508 /* libiconv.tbd in Frameworks */ = {isa = PBXBuildFile; fileRef = 5C764E7B279C71D4000C6508 /* libiconv.tbd */; }; @@ -57,10 +59,11 @@ /* End PBXContainerItemProxy section */ /* Begin PBXFileReference section */ - 5C764E5D279C70DE000C6508 /* libgmp.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; path = libgmp.a; sourceTree = ""; }; - 5C764E5E279C70DE000C6508 /* libgmpxx.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; path = libgmpxx.a; sourceTree = ""; }; - 5C764E5F279C70DE000C6508 /* libffi.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; path = libffi.a; sourceTree = ""; }; - 5C764E60279C70E0000C6508 /* libHSsimplex-chat-1.0.1-756RvUPisyT7gsYObFpxWS-ghc8.10.7.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; path = "libHSsimplex-chat-1.0.1-756RvUPisyT7gsYObFpxWS-ghc8.10.7.a"; sourceTree = ""; }; + 5C1AEB7D279F4A6400247F08 /* libHSsimplex-chat-1.0.2-FYXW0143sf06WiRQx9DgCD.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; path = "libHSsimplex-chat-1.0.2-FYXW0143sf06WiRQx9DgCD.a"; sourceTree = ""; }; + 5C1AEB7E279F4A6400247F08 /* libHSsimplex-chat-1.0.2-FYXW0143sf06WiRQx9DgCD-ghc8.10.7.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; path = "libHSsimplex-chat-1.0.2-FYXW0143sf06WiRQx9DgCD-ghc8.10.7.a"; sourceTree = ""; }; + 5C1AEB7F279F4A6400247F08 /* libffi.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; path = libffi.a; sourceTree = ""; }; + 5C1AEB80279F4A6400247F08 /* libgmp.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; path = libgmp.a; sourceTree = ""; }; + 5C1AEB81279F4A6400247F08 /* libgmpxx.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; path = libgmpxx.a; sourceTree = ""; }; 5C764E7B279C71D4000C6508 /* libiconv.tbd */ = {isa = PBXFileReference; lastKnownFileType = "sourcecode.text-based-dylib-definition"; name = libiconv.tbd; path = Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS15.2.sdk/usr/lib/libiconv.tbd; sourceTree = DEVELOPER_DIR; }; 5C764E7C279C71DB000C6508 /* libz.tbd */ = {isa = PBXFileReference; lastKnownFileType = "sourcecode.text-based-dylib-definition"; name = libz.tbd; path = Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS15.2.sdk/usr/lib/libz.tbd; sourceTree = DEVELOPER_DIR; }; 5C764E7D279C7275000C6508 /* SimpleX (iOS)-Bridging-Header.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "SimpleX (iOS)-Bridging-Header.h"; sourceTree = ""; }; @@ -87,12 +90,13 @@ isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; files = ( - 5C764E67279C70E0000C6508 /* libHSsimplex-chat-1.0.1-756RvUPisyT7gsYObFpxWS-ghc8.10.7.a in Frameworks */, 5C764E83279C748B000C6508 /* libz.tbd in Frameworks */, - 5C764E63279C70E0000C6508 /* libgmpxx.a in Frameworks */, - 5C764E65279C70E0000C6508 /* libffi.a in Frameworks */, - 5C764E61279C70E0000C6508 /* libgmp.a in Frameworks */, + 5C1AEB84279F4A6400247F08 /* libHSsimplex-chat-1.0.2-FYXW0143sf06WiRQx9DgCD-ghc8.10.7.a in Frameworks */, 5C764E82279C748B000C6508 /* libiconv.tbd in Frameworks */, + 5C1AEB86279F4A6400247F08 /* libffi.a in Frameworks */, + 5C1AEB88279F4A6400247F08 /* libgmp.a in Frameworks */, + 5C1AEB82279F4A6400247F08 /* libHSsimplex-chat-1.0.2-FYXW0143sf06WiRQx9DgCD.a in Frameworks */, + 5C1AEB8A279F4A6400247F08 /* libgmpxx.a in Frameworks */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -100,12 +104,13 @@ isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; files = ( - 5C764E68279C70E0000C6508 /* libHSsimplex-chat-1.0.1-756RvUPisyT7gsYObFpxWS-ghc8.10.7.a in Frameworks */, 5C764E85279C748C000C6508 /* libz.tbd in Frameworks */, - 5C764E64279C70E0000C6508 /* libgmpxx.a in Frameworks */, - 5C764E66279C70E0000C6508 /* libffi.a in Frameworks */, - 5C764E62279C70E0000C6508 /* libgmp.a in Frameworks */, + 5C1AEB85279F4A6400247F08 /* libHSsimplex-chat-1.0.2-FYXW0143sf06WiRQx9DgCD-ghc8.10.7.a in Frameworks */, 5C764E84279C748C000C6508 /* libiconv.tbd in Frameworks */, + 5C1AEB87279F4A6400247F08 /* libffi.a in Frameworks */, + 5C1AEB89279F4A6400247F08 /* libgmp.a in Frameworks */, + 5C1AEB83279F4A6400247F08 /* libHSsimplex-chat-1.0.2-FYXW0143sf06WiRQx9DgCD.a in Frameworks */, + 5C1AEB8B279F4A6400247F08 /* libgmpxx.a in Frameworks */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -129,10 +134,11 @@ 5C764E5C279C70B7000C6508 /* Libraries */ = { isa = PBXGroup; children = ( - 5C764E5F279C70DE000C6508 /* libffi.a */, - 5C764E5D279C70DE000C6508 /* libgmp.a */, - 5C764E5E279C70DE000C6508 /* libgmpxx.a */, - 5C764E60279C70E0000C6508 /* libHSsimplex-chat-1.0.1-756RvUPisyT7gsYObFpxWS-ghc8.10.7.a */, + 5C1AEB7F279F4A6400247F08 /* libffi.a */, + 5C1AEB80279F4A6400247F08 /* libgmp.a */, + 5C1AEB81279F4A6400247F08 /* libgmpxx.a */, + 5C1AEB7E279F4A6400247F08 /* libHSsimplex-chat-1.0.2-FYXW0143sf06WiRQx9DgCD-ghc8.10.7.a */, + 5C1AEB7D279F4A6400247F08 /* libHSsimplex-chat-1.0.2-FYXW0143sf06WiRQx9DgCD.a */, ); path = Libraries; sourceTree = ""; @@ -572,6 +578,8 @@ LIBRARY_SEARCH_PATHS = ( "$(inherited)", "$(PROJECT_DIR)/Libraries", + "$(PROJECT_DIR)/Libraries/ios", + "$(PROJECT_DIR)/Libraries/sim", ); MARKETING_VERSION = 1.0; PRODUCT_BUNDLE_IDENTIFIER = chat.simplex.app; @@ -610,6 +618,8 @@ LIBRARY_SEARCH_PATHS = ( "$(inherited)", "$(PROJECT_DIR)/Libraries", + "$(PROJECT_DIR)/Libraries/ios", + "$(PROJECT_DIR)/Libraries/sim", ); MARKETING_VERSION = 1.0; PRODUCT_BUNDLE_IDENTIFIER = chat.simplex.app; @@ -630,6 +640,7 @@ ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor; CLANG_ENABLE_MODULES = YES; CODE_SIGN_ENTITLEMENTS = "SimpleX (macOS)Debug.entitlements"; + CODE_SIGN_IDENTITY = "-"; CODE_SIGN_STYLE = Automatic; COMBINE_HIDPI_IMAGES = YES; CURRENT_PROJECT_VERSION = 1; @@ -646,6 +657,8 @@ LIBRARY_SEARCH_PATHS = ( "$(inherited)", "$(PROJECT_DIR)/Libraries", + "$(PROJECT_DIR)/Libraries/ios", + "$(PROJECT_DIR)/Libraries/sim", ); MACOSX_DEPLOYMENT_TARGET = 12.1; MARKETING_VERSION = 1.0; @@ -682,6 +695,8 @@ LIBRARY_SEARCH_PATHS = ( "$(inherited)", "$(PROJECT_DIR)/Libraries", + "$(PROJECT_DIR)/Libraries/ios", + "$(PROJECT_DIR)/Libraries/sim", ); MACOSX_DEPLOYMENT_TARGET = 12.1; MARKETING_VERSION = 1.0; diff --git a/src/Simplex/Chat/Mobile.hs b/src/Simplex/Chat/Mobile.hs index 8b3fc64c9..0f9940bcc 100644 --- a/src/Simplex/Chat/Mobile.hs +++ b/src/Simplex/Chat/Mobile.hs @@ -1,3 +1,4 @@ +{-# LANGUAGE DeriveGeneric #-} {-# LANGUAGE DuplicateRecordFields #-} {-# LANGUAGE LambdaCase #-} {-# LANGUAGE NamedFieldPuns #-} @@ -9,20 +10,23 @@ import Control.Concurrent (forkIO) import Control.Concurrent.STM import Control.Monad.Except import Control.Monad.Reader -import Data.Aeson ((.=)) +import Data.Aeson (ToJSON (..), (.=)) import qualified Data.Aeson as J import qualified Data.Aeson.Encoding as JE +import qualified Data.ByteString.Base64.URL as U import qualified Data.ByteString.Char8 as B import qualified Data.ByteString.Lazy.Char8 as LB import Data.List (find) import Foreign.C.String import Foreign.StablePtr +import GHC.Generics import Simplex.Chat import Simplex.Chat.Controller import Simplex.Chat.Options import Simplex.Chat.Store import Simplex.Chat.Types import Simplex.Chat.View +import Simplex.Messaging.Protocol (CorrId (..)) foreign export ccall "chat_init_store" cChatInitStore :: CString -> IO (StablePtr ChatStore) @@ -34,7 +38,7 @@ foreign export ccall "chat_start" cChatStart :: StablePtr ChatStore -> IO (Stabl foreign export ccall "chat_send_cmd" cChatSendCmd :: StablePtr ChatController -> CString -> IO CJSONString -foreign export ccall "chat_recv_msg" cChatRecvMsg :: StablePtr ChatController -> IO CString +foreign export ccall "chat_recv_msg" cChatRecvMsg :: StablePtr ChatController -> IO CJSONString -- | creates or connects to chat store cChatInitStore :: CString -> IO (StablePtr ChatStore) @@ -63,7 +67,7 @@ cChatSendCmd cPtr cCmd = do newCString =<< chatSendCmd c cmd -- | receive message from chat (blocking) -cChatRecvMsg :: StablePtr ChatController -> IO CString +cChatRecvMsg :: StablePtr ChatController -> IO CJSONString cChatRecvMsg cc = deRefStablePtr cc >>= chatRecvMsg >>= newCString mobileChatOpts :: ChatOpts @@ -115,18 +119,33 @@ chatStart ChatStore {dbFilePrefix, chatStore} = do pure cc chatSendCmd :: ChatController -> String -> IO JSONString -chatSendCmd cc s = crToJSON <$> runReaderT (execChatCommand s) cc +chatSendCmd cc s = crToJSON (CorrId "") <$> runReaderT (execChatCommand s) cc -chatRecvMsg :: ChatController -> IO String -chatRecvMsg ChatController {outputQ} = serializeChatResponse . snd <$> atomically (readTBQueue outputQ) +chatRecvMsg :: ChatController -> IO JSONString +chatRecvMsg ChatController {outputQ} = json <$> atomically (readTBQueue outputQ) + where + json (corrId, resp) = crToJSON corrId resp jsonObject :: J.Series -> JSONString jsonObject = LB.unpack . JE.encodingToLazyByteString . J.pairs -crToJSON :: ChatResponse -> JSONString -crToJSON = \case - CRUserProfile p -> o "profile" $ J.object ["profile" .= p] - r -> o "terminal" $ J.object ["response" .= serializeChatResponse r] +crToJSON :: CorrId -> ChatResponse -> JSONString +crToJSON corrId = LB.unpack . J.encode . crToAPI corrId + +crToAPI :: CorrId -> ChatResponse -> APIResponse +crToAPI (CorrId cId) = \case + CRUserProfile p -> api "profile" $ J.object ["profile" .= p] + r -> api "terminal" $ J.object ["output" .= serializeChatResponse r] where - o :: String -> J.Value -> JSONString - o tp params = jsonObject ("type" .= tp <> "params" .= params) + corr = if B.null cId then Nothing else Just . B.unpack $ U.encode cId + api tag args = APIResponse {corr, tag, args} + +data APIResponse = APIResponse + { -- | optional correlation ID for async command responses + corr :: Maybe String, + tag :: String, + args :: J.Value + } + deriving (Generic) + +instance ToJSON APIResponse where toEncoding = J.genericToEncoding J.defaultOptions {J.omitNothingFields = True}