From 08d86856c12ae45a34bf7aa3d9532aec5f1f4d46 Mon Sep 17 00:00:00 2001 From: gahag Date: Mon, 5 Oct 2020 15:29:53 -0300 Subject: [PATCH 1/2] implement websocket compression setting (fix #3292) As discussed, the websocket package has a compression setting built-in. This commit implements the wiring to allow such configuration through the `connection-compression` command line flag, or the `HASURA_GRAPHQL_CONNECTION_COMPRESSION` environment variable. --- CHANGELOG.md | 1 + server/src-lib/Hasura/App.hs | 1 + server/src-lib/Hasura/Server/App.hs | 5 +- server/src-lib/Hasura/Server/Init.hs | 27 +++++++++- server/src-lib/Hasura/Server/Init/Config.hs | 55 +++++++++++---------- 5 files changed, 60 insertions(+), 29 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index c5be2875b0200..0e74321bddc32 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -50,6 +50,7 @@ This release contains the [PDV refactor (#4111)](https://github.com/hasura/graph (Add entries here in the order of: server, console, cli, docs, others) +- server: add `--connection-compression` command-line flag for enabling websocket compression (fix #3292) - server: some mutations that cannot be performed will no longer be in the schema (for instance, `delete_by_pk` mutations won't be shown to users that do not have select permissions on all primary keys) (#4111) - server: miscellaneous description changes (#4111) - server: treat the absence of `backend_only` configuration and `backend_only: false` equally (closing #5059) (#4111) diff --git a/server/src-lib/Hasura/App.hs b/server/src-lib/Hasura/App.hs index 8560086dc282b..f3887da89b701 100644 --- a/server/src-lib/Hasura/App.hs +++ b/server/src-lib/Hasura/App.hs @@ -363,6 +363,7 @@ runHGEServer env ServeOptions{..} InitCtx{..} pgExecCtx initTime shutdownApp pos postPollHook _icSchemaCache ekgStore + soConnectionOptions -- log inconsistent schema objects inconsObjs <- scInconsistentObjs <$> liftIO (getSCFromRef cacheRef) diff --git a/server/src-lib/Hasura/Server/App.hs b/server/src-lib/Hasura/Server/App.hs index 23a9bc3015213..7f6fcc18ca788 100644 --- a/server/src-lib/Hasura/Server/App.hs +++ b/server/src-lib/Hasura/Server/App.hs @@ -603,9 +603,10 @@ mkWaiApp -> Maybe EL.LiveQueryPostPollHook -> (RebuildableSchemaCache Run, Maybe UTCTime) -> EKG.Store + -> WS.ConnectionOptions -> m HasuraApp mkWaiApp env isoLevel logger sqlGenCtx enableAL pool pgExecCtxCustom ci httpManager mode corsCfg enableConsole consoleAssetsDir - enableTelemetry instanceId apis lqOpts _ {- planCacheOptions -} responseErrorsConfig liveQueryHook (schemaCache, cacheBuiltTime) ekgStore = do + enableTelemetry instanceId apis lqOpts _ {- planCacheOptions -} responseErrorsConfig liveQueryHook (schemaCache, cacheBuiltTime) ekgStore connectionOptions = do -- See Note [Temporarily disabling query plan caching] -- (planCache, schemaCacheRef) <- initialiseCache @@ -646,7 +647,7 @@ mkWaiApp env isoLevel logger sqlGenCtx enableAL pool pgExecCtxCustom ci httpMana stopWSServer = WS.stopWSServerApp wsServerEnv waiApp <- liftWithStateless $ \lowerIO -> - pure $ WSC.websocketsOr WS.defaultConnectionOptions (\ip conn -> lowerIO $ wsServerApp ip conn) spockApp + pure $ WSC.websocketsOr connectionOptions (\ip conn -> lowerIO $ wsServerApp ip conn) spockApp return $ HasuraApp waiApp schemaCacheRef cacheBuiltTime stopWSServer where diff --git a/server/src-lib/Hasura/Server/Init.hs b/server/src-lib/Hasura/Server/Init.hs index 55fa5ed60c173..43185b2fc71f8 100644 --- a/server/src-lib/Hasura/Server/Init.hs +++ b/server/src-lib/Hasura/Server/Init.hs @@ -20,6 +20,7 @@ import qualified Text.PrettyPrint.ANSI.Leijen as PP import Data.FileEmbed (embedStringFile) import Data.Time (NominalDiffTime) import Network.Wai.Handler.Warp (HostPreference) +import qualified Network.WebSockets as WS import Options.Applicative import qualified Hasura.Cache.Bounded as Cache @@ -170,12 +171,22 @@ mkServeOptions rso = do eventsFetchInterval <- withEnv (rsoEventsFetchInterval rso) (fst eventsFetchIntervalEnv) logHeadersFromEnv <- withEnvBool (rsoLogHeadersFromEnv rso) (fst logHeadersFromEnvEnv) + connectionCompressionFromEnv <- withEnvBool (rsoConnectionCompression rso) $ + fst connectionCompressionEnv + + let connectionOptions = WS.defaultConnectionOptions { + WS.connectionCompressionOptions = + if connectionCompressionFromEnv + then WS.PermessageDeflateCompression WS.defaultPermessageDeflate + else WS.NoCompression + } + return $ ServeOptions port host connParams txIso adminScrt authHook jwtSecret unAuthRole corsCfg enableConsole consoleAssetsDir enableTelemetry strfyNum enabledAPIs lqOpts enableAL enabledLogs serverLogLevel planCacheOptions internalErrorsConfig eventsHttpPoolSize eventsFetchInterval - logHeadersFromEnv + logHeadersFromEnv connectionOptions where #ifdef DeveloperAPIs defaultAPIs = [METADATA,GRAPHQL,PGDUMP,CONFIG,DEVELOPER] @@ -931,6 +942,7 @@ serveOptsToLog so = , "enabled_log_types" J..= soEnabledLogTypes so , "log_level" J..= soLogLevel so , "plan_cache_options" J..= soPlanCacheOptions so + , "websocket_compression_options" J..= show (WS.connectionCompressionOptions . soConnectionOptions $ so) ] mkGenericStrLog :: L.LogLevel -> T.Text -> String -> StartupLog @@ -976,6 +988,7 @@ serveOptionsParser = <*> parseGraphqlEventsHttpPoolSize <*> parseGraphqlEventsFetchInterval <*> parseLogHeadersFromEnv + <*> parseConnectionCompression -- | This implements the mapping between application versions -- and catalog schema versions. @@ -1010,3 +1023,15 @@ downgradeOptionsParser = ( long ("to-" <> v) <> help ("Downgrade to graphql-engine version " <> v <> " (equivalent to --to-catalog-version " <> catalogVersion <> ")") ) + +connectionCompressionEnv :: (String, String) +connectionCompressionEnv = + ( "HASURA_GRAPHQL_CONNECTION_COMPRESSION" + , "Enable Websocket Compression (default: false)" + ) + +parseConnectionCompression :: Parser Bool +parseConnectionCompression = + switch ( long "connection-compression" <> + help (snd connectionCompressionEnv) + ) diff --git a/server/src-lib/Hasura/Server/Init/Config.hs b/server/src-lib/Hasura/Server/Init/Config.hs index 005c81eeeb713..b5a69dacc6b7b 100644 --- a/server/src-lib/Hasura/Server/Init/Config.hs +++ b/server/src-lib/Hasura/Server/Init/Config.hs @@ -12,6 +12,7 @@ import qualified Database.PG.Query as Q import Data.Char (toLower) import Data.Time import Network.Wai.Handler.Warp (HostPreference) +import qualified Network.WebSockets as WS import qualified Hasura.Cache.Bounded as Cache import qualified Hasura.GraphQL.Execute.LiveQuery as LQ @@ -38,32 +39,33 @@ type RawAuthHook = AuthHookG (Maybe T.Text) (Maybe AuthHookType) data RawServeOptions impl = RawServeOptions - { rsoPort :: !(Maybe Int) - , rsoHost :: !(Maybe HostPreference) - , rsoConnParams :: !RawConnParams - , rsoTxIso :: !(Maybe Q.TxIsolation) - , rsoAdminSecret :: !(Maybe AdminSecretHash) - , rsoAuthHook :: !RawAuthHook - , rsoJwtSecret :: !(Maybe JWTConfig) - , rsoUnAuthRole :: !(Maybe RoleName) - , rsoCorsConfig :: !(Maybe CorsConfig) - , rsoEnableConsole :: !Bool - , rsoConsoleAssetsDir :: !(Maybe Text) - , rsoEnableTelemetry :: !(Maybe Bool) - , rsoWsReadCookie :: !Bool - , rsoStringifyNum :: !Bool - , rsoEnabledAPIs :: !(Maybe [API]) - , rsoMxRefetchInt :: !(Maybe LQ.RefetchInterval) - , rsoMxBatchSize :: !(Maybe LQ.BatchSize) - , rsoEnableAllowlist :: !Bool - , rsoEnabledLogTypes :: !(Maybe [L.EngineLogType impl]) - , rsoLogLevel :: !(Maybe L.LogLevel) - , rsoPlanCacheSize :: !(Maybe Cache.CacheSize) - , rsoDevMode :: !Bool - , rsoAdminInternalErrors :: !(Maybe Bool) - , rsoEventsHttpPoolSize :: !(Maybe Int) - , rsoEventsFetchInterval :: !(Maybe Milliseconds) - , rsoLogHeadersFromEnv :: !Bool + { rsoPort :: !(Maybe Int) + , rsoHost :: !(Maybe HostPreference) + , rsoConnParams :: !RawConnParams + , rsoTxIso :: !(Maybe Q.TxIsolation) + , rsoAdminSecret :: !(Maybe AdminSecretHash) + , rsoAuthHook :: !RawAuthHook + , rsoJwtSecret :: !(Maybe JWTConfig) + , rsoUnAuthRole :: !(Maybe RoleName) + , rsoCorsConfig :: !(Maybe CorsConfig) + , rsoEnableConsole :: !Bool + , rsoConsoleAssetsDir :: !(Maybe Text) + , rsoEnableTelemetry :: !(Maybe Bool) + , rsoWsReadCookie :: !Bool + , rsoStringifyNum :: !Bool + , rsoEnabledAPIs :: !(Maybe [API]) + , rsoMxRefetchInt :: !(Maybe LQ.RefetchInterval) + , rsoMxBatchSize :: !(Maybe LQ.BatchSize) + , rsoEnableAllowlist :: !Bool + , rsoEnabledLogTypes :: !(Maybe [L.EngineLogType impl]) + , rsoLogLevel :: !(Maybe L.LogLevel) + , rsoPlanCacheSize :: !(Maybe Cache.CacheSize) + , rsoDevMode :: !Bool + , rsoAdminInternalErrors :: !(Maybe Bool) + , rsoEventsHttpPoolSize :: !(Maybe Int) + , rsoEventsFetchInterval :: !(Maybe Milliseconds) + , rsoLogHeadersFromEnv :: !Bool + , rsoConnectionCompression :: !Bool } -- | @'ResponseInternalErrorsConfig' represents the encoding of the internal @@ -106,6 +108,7 @@ data ServeOptions impl , soEventsHttpPoolSize :: !(Maybe Int) , soEventsFetchInterval :: !(Maybe Milliseconds) , soLogHeadersFromEnv :: !Bool + , soConnectionOptions :: !WS.ConnectionOptions } data DowngradeOptions From f559c0060c99123f1aac7808cf94e140bc33e8d7 Mon Sep 17 00:00:00 2001 From: gahag Date: Tue, 6 Oct 2020 11:34:44 -0300 Subject: [PATCH 2/2] rename connectionCompression to webSocketCompression As requested in code review. --- CHANGELOG.md | 2 +- server/src-lib/Hasura/Server/Init.hs | 22 ++++++++++----------- server/src-lib/Hasura/Server/Init/Config.hs | 2 +- 3 files changed, 13 insertions(+), 13 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 0e74321bddc32..fe8a79645c024 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -50,7 +50,7 @@ This release contains the [PDV refactor (#4111)](https://github.com/hasura/graph (Add entries here in the order of: server, console, cli, docs, others) -- server: add `--connection-compression` command-line flag for enabling websocket compression (fix #3292) +- server: add `--websocket-compression` command-line flag for enabling websocket compression (fix #3292) - server: some mutations that cannot be performed will no longer be in the schema (for instance, `delete_by_pk` mutations won't be shown to users that do not have select permissions on all primary keys) (#4111) - server: miscellaneous description changes (#4111) - server: treat the absence of `backend_only` configuration and `backend_only: false` equally (closing #5059) (#4111) diff --git a/server/src-lib/Hasura/Server/Init.hs b/server/src-lib/Hasura/Server/Init.hs index 43185b2fc71f8..c78e9257f1511 100644 --- a/server/src-lib/Hasura/Server/Init.hs +++ b/server/src-lib/Hasura/Server/Init.hs @@ -171,12 +171,12 @@ mkServeOptions rso = do eventsFetchInterval <- withEnv (rsoEventsFetchInterval rso) (fst eventsFetchIntervalEnv) logHeadersFromEnv <- withEnvBool (rsoLogHeadersFromEnv rso) (fst logHeadersFromEnvEnv) - connectionCompressionFromEnv <- withEnvBool (rsoConnectionCompression rso) $ - fst connectionCompressionEnv + webSocketCompressionFromEnv <- withEnvBool (rsoWebSocketCompression rso) $ + fst webSocketCompressionEnv let connectionOptions = WS.defaultConnectionOptions { WS.connectionCompressionOptions = - if connectionCompressionFromEnv + if webSocketCompressionFromEnv then WS.PermessageDeflateCompression WS.defaultPermessageDeflate else WS.NoCompression } @@ -988,7 +988,7 @@ serveOptionsParser = <*> parseGraphqlEventsHttpPoolSize <*> parseGraphqlEventsFetchInterval <*> parseLogHeadersFromEnv - <*> parseConnectionCompression + <*> parseWebSocketCompression -- | This implements the mapping between application versions -- and catalog schema versions. @@ -1024,14 +1024,14 @@ downgradeOptionsParser = help ("Downgrade to graphql-engine version " <> v <> " (equivalent to --to-catalog-version " <> catalogVersion <> ")") ) -connectionCompressionEnv :: (String, String) -connectionCompressionEnv = +webSocketCompressionEnv :: (String, String) +webSocketCompressionEnv = ( "HASURA_GRAPHQL_CONNECTION_COMPRESSION" - , "Enable Websocket Compression (default: false)" + , "Enable WebSocket permessage-deflate compression (default: false)" ) -parseConnectionCompression :: Parser Bool -parseConnectionCompression = - switch ( long "connection-compression" <> - help (snd connectionCompressionEnv) +parseWebSocketCompression :: Parser Bool +parseWebSocketCompression = + switch ( long "websocket-compression" <> + help (snd webSocketCompressionEnv) ) diff --git a/server/src-lib/Hasura/Server/Init/Config.hs b/server/src-lib/Hasura/Server/Init/Config.hs index b5a69dacc6b7b..edbbee3188730 100644 --- a/server/src-lib/Hasura/Server/Init/Config.hs +++ b/server/src-lib/Hasura/Server/Init/Config.hs @@ -65,7 +65,7 @@ data RawServeOptions impl , rsoEventsHttpPoolSize :: !(Maybe Int) , rsoEventsFetchInterval :: !(Maybe Milliseconds) , rsoLogHeadersFromEnv :: !Bool - , rsoConnectionCompression :: !Bool + , rsoWebSocketCompression :: !Bool } -- | @'ResponseInternalErrorsConfig' represents the encoding of the internal