Fix bug in HTTP delivery actor storage, delivery wasn't working

This commit is contained in:
Pere Lev 2024-03-14 00:49:18 +02:00
parent 1c10d3fb03
commit 6e55659410
No known key found for this signature in database
GPG key ID: 5252C5C863E5E57D
2 changed files with 34 additions and 9 deletions

View file

@ -1,6 +1,6 @@
{- This file is part of Vervis. {- This file is part of Vervis.
- -
- Written in 2023 by fr33domlover <fr33domlover@riseup.net>. - Written in 2023, 2024 by fr33domlover <fr33domlover@riseup.net>.
- -
- Copying is an act of love. Please copy, reuse and share. - Copying is an act of love. Please copy, reuse and share.
- -
@ -114,6 +114,7 @@ module Database.Persist.Box.Internal
where where
import Control.Exception.Base import Control.Exception.Base
import Control.Monad
import Control.Monad.IO.Class import Control.Monad.IO.Class
import Control.Monad.IO.Unlift import Control.Monad.IO.Unlift
import Control.Monad.Logger.CallStack import Control.Monad.Logger.CallStack
@ -121,6 +122,7 @@ import Control.Monad.Trans.Class
import Data.ByteString (ByteString) import Data.ByteString (ByteString)
import Data.Int import Data.Int
import Data.Kind import Data.Kind
import Data.Maybe
import Data.Proxy import Data.Proxy
import Data.Text (Text) import Data.Text (Text)
import Database.Persist import Database.Persist
@ -165,7 +167,7 @@ createCellIfNeeded
createCellIfNeeded p = do createCellIfNeeded p = do
r <- r <-
rawSql rawSql
"SELECT name FROM sqlite_schema WHERE type='table' AND name=?" "SELECT name FROM sqlite_master WHERE type='table' AND name=?"
[PersistText "cell"] [PersistText "cell"]
case r of case r of
[] -> [] ->
@ -176,7 +178,7 @@ createCellIfNeeded p = do
] ]
in rawExecute query [] in rawExecute query []
[Single (_ :: a)] -> pure () [Single (_ :: a)] -> pure ()
_ -> error "Multiple cell tables in sqlite_schema" _ -> error "Multiple cell tables in sqlite_master"
model :: QuasiQuoter model :: QuasiQuoter
model = PS.model "" model = PS.model ""
@ -198,6 +200,7 @@ class Boxable a where
--type MigrationRecipes a :: * -> * --type MigrationRecipes a :: * -> *
--migrateBox :: (MonadIO m, MonadLogger m, MonadMigrateBox m) => MigrationRecipe a m -> SqlPersistT m (Either Text (Int, Int)) --migrateBox :: (MonadIO m, MonadLogger m, MonadMigrateBox m) => MigrationRecipe a m -> SqlPersistT m (Either Text (Int, Int))
createBoxStorageIfNeeded :: MonadIO m => Proxy a -> SqlPersistT m () createBoxStorageIfNeeded :: MonadIO m => Proxy a -> SqlPersistT m ()
getB :: MonadIO m => SqlPersistT m (Maybe a)
bestowB :: MonadIO m => a -> SqlPersistT m () bestowB :: MonadIO m => a -> SqlPersistT m ()
obtainB :: MonadIO m => SqlPersistT m a obtainB :: MonadIO m => SqlPersistT m a
@ -220,6 +223,9 @@ bestow = BoxPersistT . bestowB . wrapBF @(BV a) @a
obtain :: forall m a. (MonadIO m, BoxableVia a) => BoxPersistT a m a obtain :: forall m a. (MonadIO m, BoxableVia a) => BoxPersistT a m a
obtain = BoxPersistT $ unwrapBF @(BV a) @a <$> obtainB obtain = BoxPersistT $ unwrapBF @(BV a) @a <$> obtainB
get_b :: forall m a. (MonadIO m, BoxableVia a) => BoxPersistT a m (Maybe a)
get_b = BoxPersistT $ fmap (unwrapBF @(BV a) @a) <$> getB
newtype BoxableRecord a = BoxableRecord { unBoxableRecord :: a } newtype BoxableRecord a = BoxableRecord { unBoxableRecord :: a }
instance BoxableFormat BoxableRecord where instance BoxableFormat BoxableRecord where
@ -236,6 +242,7 @@ instance (PersistRecordBackend a SqlBackend, ToBackendKey SqlBackend a) => Boxab
--type MigrationRecipe (BoxablePersist a) m = [Migration SqlBackend m] --type MigrationRecipe (BoxablePersist a) m = [Migration SqlBackend m]
--migrateBox ms = second (,length ms) <$> runMigrations schemaBackend? "" 1 ms --migrateBox ms = second (,length ms) <$> runMigrations schemaBackend? "" 1 ms
createBoxStorageIfNeeded = createEntityIfNeeded . fmap unBoxableRecord createBoxStorageIfNeeded = createEntityIfNeeded . fmap unBoxableRecord
getB = fmap BoxableRecord <$> get key
bestowB (BoxableRecord r) = repsert key r bestowB (BoxableRecord r) = repsert key r
obtainB = BoxableRecord <$> getJust key obtainB = BoxableRecord <$> getJust key
@ -253,6 +260,14 @@ instance PersistFieldSql a => Boxable (BoxableField a) where
--type MigrationRecipe (BoxablePersist a) = ??? --type MigrationRecipe (BoxablePersist a) = ???
--migrateBox ms = ??? --migrateBox ms = ???
createBoxStorageIfNeeded = createCellIfNeeded . fmap unBoxableField createBoxStorageIfNeeded = createCellIfNeeded . fmap unBoxableField
getB = do
r <- rawSql query [toPersistValue keyN]
case r of
[] -> return Nothing
[Single v] -> return $ Just $ BoxableField v
_ -> liftIO $ throwIO $ BoxException "getB: multiple rows found"
where
query = "SELECT value FROM cell WHERE id=?"
bestowB (BoxableField v) = bestowB (BoxableField v) =
rawExecute query [toPersistValue keyN, toPersistValue v] rawExecute query [toPersistValue keyN, toPersistValue v]
where where
@ -300,6 +315,7 @@ instance (Typeable a, Show a, Read a) => Boxable (BoxableShow a) where
--migrateBox ms = ??? --migrateBox ms = ???
createBoxStorageIfNeeded = createBoxStorageIfNeeded =
createCellIfNeeded . fmap (WrapShow . unBoxableShow) createCellIfNeeded . fmap (WrapShow . unBoxableShow)
getB = fmap (BoxableShow . unWrapShow . unBoxableField) <$> getB
bestowB = bestowB . BoxableField . WrapShow . unBoxableShow bestowB = bestowB . BoxableField . WrapShow . unBoxableShow
obtainB = BoxableShow . unWrapShow . unBoxableField <$> obtainB obtainB = BoxableShow . unWrapShow . unBoxableField <$> obtainB
@ -334,6 +350,7 @@ instance (Typeable a, A.FromJSON a, A.ToJSON a) => Boxable (BoxableJSON a) where
--migrateBox ms = ??? --migrateBox ms = ???
createBoxStorageIfNeeded = createBoxStorageIfNeeded =
createCellIfNeeded . fmap (WrapJSON . unBoxableJSON) createCellIfNeeded . fmap (WrapJSON . unBoxableJSON)
getB = fmap (BoxableJSON . unWrapJSON . unBoxableField) <$> getB
bestowB = bestowB . BoxableField . WrapJSON . unBoxableJSON bestowB = bestowB . BoxableField . WrapJSON . unBoxableJSON
obtainB = BoxableJSON . unWrapJSON . unBoxableField <$> obtainB obtainB = BoxableJSON . unWrapJSON . unBoxableField <$> obtainB
@ -362,6 +379,7 @@ instance (Typeable a, S.Serialize a) => Boxable (BoxableSerialize a) where
--migrateBox ms = ??? --migrateBox ms = ???
createBoxStorageIfNeeded = createBoxStorageIfNeeded =
createCellIfNeeded . fmap (WrapSerialize . unBoxableSerialize) createCellIfNeeded . fmap (WrapSerialize . unBoxableSerialize)
getB = fmap (BoxableSerialize . unWrapSerialize . unBoxableField) <$> getB
bestowB = bestowB . BoxableField . WrapSerialize . unBoxableSerialize bestowB = bestowB . BoxableField . WrapSerialize . unBoxableSerialize
obtainB = BoxableSerialize . unWrapSerialize . unBoxableField <$> obtainB obtainB = BoxableSerialize . unWrapSerialize . unBoxableField <$> obtainB
@ -382,6 +400,8 @@ loadBox path val = do
let proxy :: a -> Proxy (BV a a) let proxy :: a -> Proxy (BV a a)
proxy _ = Proxy proxy _ = Proxy
BoxPersistT $ createBoxStorageIfNeeded $ proxy val BoxPersistT $ createBoxStorageIfNeeded $ proxy val
mval <- get_b
when (isNothing mval) $ bestow val
{- {-
r <- migrateBox migrations r <- migrateBox migrations
Left err -> do Left err -> do

View file

@ -1,6 +1,6 @@
{- This file is part of Vervis. {- This file is part of Vervis.
- -
- Written in 2023 by fr33domlover <fr33domlover@riseup.net>. - Written in 2023, 2024 by fr33domlover <fr33domlover@riseup.net>.
- -
- Copying is an act of love. Please copy, reuse and share. - Copying is an act of love. Please copy, reuse and share.
- -
@ -47,6 +47,8 @@ import Data.Traversable
import Database.Persist.Sql import Database.Persist.Sql
import Network.HTTP.Client (Manager) import Network.HTTP.Client (Manager)
import Network.HTTP.Types.Header (HeaderName) import Network.HTTP.Types.Header (HeaderName)
import Network.HTTP.Types.URI (urlEncode, urlDecode)
import System.FilePath ((</>))
import System.Directory import System.Directory
import Web.Hashids import Web.Hashids
@ -54,6 +56,7 @@ import qualified Data.Aeson as A
import qualified Data.ByteString.Lazy as BL import qualified Data.ByteString.Lazy as BL
import qualified Data.HashSet as HS import qualified Data.HashSet as HS
import qualified Data.Text as T import qualified Data.Text as T
import qualified Data.Text.Encoding as TE
import Control.Concurrent.Actor import Control.Concurrent.Actor
import Database.Persist.Box import Database.Persist.Box
@ -110,6 +113,7 @@ data DeliveryTheater u = DeliveryTheater
, _dtHeaders :: NonEmpty HeaderName , _dtHeaders :: NonEmpty HeaderName
, _dtDelay :: Int , _dtDelay :: Int
, _dtLog :: LogFunc , _dtLog :: LogFunc
, _dtDir :: OsPath
, _dtTheater :: TheaterFor (Env u) , _dtTheater :: TheaterFor (Env u)
} }
@ -189,20 +193,21 @@ startDeliveryTheater headers micros manager logFunc dbRootDir = do
entries <- listDirectory dbRootDir entries <- listDirectory dbRootDir
actors <- for entries $ \ path -> do actors <- for entries $ \ path -> do
path' <- T.pack <$> decodeUtf path path' <- T.pack <$> decodeUtf path
path'' <- either throwIO pure $ TE.decodeUtf8' $ urlDecode False $ TE.encodeUtf8 path'
u <- u <-
case parseObjURI path' of case parseObjURI path'' of
Left e -> Left e ->
error $ error $
"Failed to parse URI-named SQLite db filename: " ++ e "Failed to parse URI-named SQLite db filename: " ++ e
Right uri -> return uri Right uri -> return uri
env <- mkEnv logFunc path env <- mkEnv logFunc $ dbRootDir </> path
return (u, env, behavior manager headers micros u) return (u, env, behavior manager headers micros u)
DeliveryTheater manager headers micros logFunc <$> startTheater logFunc actors DeliveryTheater manager headers micros logFunc dbRootDir <$> startTheater logFunc actors
sendHttp :: UriMode u => DeliveryTheater u -> Method u -> [ObjURI u] -> IO () sendHttp :: UriMode u => DeliveryTheater u -> Method u -> [ObjURI u] -> IO ()
sendHttp (DeliveryTheater manager headers micros logFunc theater) method recips = do sendHttp (DeliveryTheater manager headers micros logFunc root theater) method recips = do
for_ recips $ \ u -> for_ recips $ \ u ->
let makeEnv = encodeUtf (T.unpack $ renderObjURI u) >>= mkEnv logFunc let makeEnv = either throwIO pure (TE.decodeUtf8' $ urlEncode False $ TE.encodeUtf8 $ renderObjURI u) >>= encodeUtf . (root </>) . T.unpack >>= mkEnv logFunc
behave = behavior manager headers micros u behave = behavior manager headers micros u
in void $ spawnIO theater u makeEnv behave in void $ spawnIO theater u makeEnv behave
sendManyIO theater (HS.fromList recips) method sendManyIO theater (HS.fromList recips) method