runService :: FilePath -> IO ()
runService configurationFilename = do
  configurationText <- Text.readFile configurationFilename
  case JSON.eitherDecode'
        $ LBS.fromChunks [Text.encodeUtf8 configurationText] of
    Left message -> do
      putStrLn $ "Invalid configuration: " ++ message
    Right configuration -> do
      database <-
        SQL.open $ Text.pack $ configurationDatabaseFilename configuration
      databaseMVar <- newMVar database
      captchaCacheMVar <- newMVar Map.empty
      allInterfaces <- getAllInterfaces
      let state = ServerState {
              serverStateDatabase = databaseMVar,
              serverStateCaptchaCache = captchaCacheMVar,
              serverStateSessionID = Nothing
            }
          serverParameters = HTTP.HTTPServerParameters {
              HTTP.serverParametersAccessLogPath = Nothing,
              HTTP.serverParametersErrorLogPath =
                Just $ configurationLogFilename configuration,
              HTTP.serverParametersDaemonize = True,
              HTTP.serverParametersUserToChangeTo =
                configurationUserName configuration,
              HTTP.serverParametersGroupToChangeTo =
                configurationGroupName configuration,
              HTTP.serverParametersForkPrimitive = forkIO,
              HTTP.serverParametersListenSockets =
                concatMap
                  (\listener ->
                     let portNumber = listenerPort listener
                         socketAddresses =
                           case listenerInterface listener of
                             Nothing ->
                               map (\interface ->
                                      Network.SockAddrInet portNumber
                                                           interface)
                                   allInterfaces
                             Just hostAddress ->
                               [Network.SockAddrInet portNumber hostAddress]
                     in map (\socketAddress ->
                               HTTP.HTTPListenSocketParameters {
                                   HTTP.listenSocketParametersAddress =
                                     socketAddress,
                                   HTTP.listenSocketParametersSecure = False
                                 })
                            socketAddresses)
                  (configurationListeners configuration)
            }
      HTTP.acceptLoop serverParameters $ evalStateT accept state
runService :: FilePath -> IO ()
runService configurationFilename = do
  configurationText <- Text.readFile configurationFilename
  case JSON.eitherDecode'
        $ LBS.fromChunks [Text.encodeUtf8 configurationText] of
    Left message -> do
      putStrLn $ "Invalid configuration: " ++ message
    Right configuration -> do
      database <-
        SQL.open $ Text.pack $ configurationDatabaseFilename configuration
      databaseMVar <- newMVar database
      captchaCacheMVar <- newMVar Map.empty
      allInterfaces <- getAllInterfaces
      let state = ServerState {
              serverStateDatabase = databaseMVar,
              serverStateCaptchaCache = captchaCacheMVar,
              serverStateSessionID = Nothing
            }
          serverParameters = HTTP.HTTPServerParameters {
              HTTP.serverParametersAccessLogPath = Nothing,
              HTTP.serverParametersErrorLogPath =
                Just $ configurationLogFilename configuration,
              HTTP.serverParametersDaemonize = True,
              HTTP.serverParametersUserToChangeTo =
                configurationUserName configuration,
              HTTP.serverParametersGroupToChangeTo =
                configurationGroupName configuration,
              HTTP.serverParametersForkPrimitive = forkIO,
              HTTP.serverParametersListenSockets =
                concatMap
                  (\listener ->
                     let portNumber = listenerPort listener
                         socketAddresses =
                           case listenerInterface listener of
                             Nothing ->
                               map (\interface ->
                                      Network.SockAddrInet portNumber
                                                           interface)
                                   allInterfaces
                             Just hostAddress ->
                               [Network.SockAddrInet portNumber hostAddress]
                     in map (\socketAddress ->
                               HTTP.HTTPListenSocketParameters {
                                   HTTP.listenSocketParametersAddress =
                                     socketAddress,
                                   HTTP.listenSocketParametersSecure = False
                                 })
                            socketAddresses)
                  (configurationListeners configuration)
            }
      HTTP.acceptLoop serverParameters $ evalStateT accept state
runService configurationFilename = do
  configurationText <- Text.readFile configurationFilename
  case JSON.eitherDecode'
        $ LBS.fromChunks [Text.encodeUtf8 configurationText] of
    Left message -> do
      putStrLn $ "Invalid configuration: " ++ message
    Right configuration -> do
      database <-
        SQL.open $ Text.pack $ configurationDatabaseFilename configuration
      databaseMVar <- newMVar database
      captchaCacheMVar <- newMVar Map.empty
      allInterfaces <- getAllInterfaces
      let state = ServerState {
              serverStateDatabase = databaseMVar,
              serverStateCaptchaCache = captchaCacheMVar,
              serverStateSessionID = Nothing
            }
          serverParameters = HTTP.HTTPServerParameters {
              HTTP.serverParametersAccessLogPath = Nothing,
              HTTP.serverParametersErrorLogPath =
                Just $ configurationLogFilename configuration,
              HTTP.serverParametersDaemonize = True,
              HTTP.serverParametersUserToChangeTo =
                configurationUserName configuration,
              HTTP.serverParametersGroupToChangeTo =
                configurationGroupName configuration,
              HTTP.serverParametersForkPrimitive = forkIO,
              HTTP.serverParametersListenSockets =
                concatMap
                  (\listener ->
                     let portNumber = listenerPort listener
                         socketAddresses =
                           case listenerInterface listener of
                             Nothing ->
                               map (\interface ->
                                      Network.SockAddrInet portNumber
                                                           interface)
                                   allInterfaces
                             Just hostAddress ->
                               [Network.SockAddrInet portNumber hostAddress]
                     in map (\socketAddress ->
                               HTTP.HTTPListenSocketParameters {
                                   HTTP.listenSocketParametersAddress =
                                     socketAddress,
                                   HTTP.listenSocketParametersSecure = False
                                 })
                            socketAddresses)
                  (configurationListeners configuration)
            }
      HTTP.acceptLoop serverParameters $ evalStateT accept state