Resolver.hs (4081B)
1 module ContentStore.Resolver 2 ( ObjectResolver(..) 3 , filesystemResolver 4 , cachedFilesystemResolver 5 , resolveObjectByHash 6 , resolveManifest 7 , resolveTree 8 ) where 9 10 import ContentStore.Alias 11 import ContentStore.Arboricx 12 import ContentStore.Filesystem 13 import ContentStore.Object 14 import Module.Manifest 15 import Research (Node(..), T, deserializeNode) 16 import qualified Research 17 18 import Data.ByteString (ByteString) 19 import Data.IORef (IORef, newIORef, readIORef, atomicModifyIORef') 20 import qualified Data.Map as Map 21 import qualified Data.Text as T 22 23 -- | Object and alias resolution capability. Module/import code should depend on 24 -- this boundary rather than on a concrete filesystem store. Future resolvers can 25 -- add trusted remotes, registries, or caches while preserving the same verified 26 -- content-addressed interface. 27 data ObjectResolver = ObjectResolver 28 { resolverAlias :: AliasKind -> T.Text -> IO (Maybe ObjectRef) 29 , resolverObject :: ObjectRef -> IO (Maybe ByteString) 30 , resolverManifest :: ObjectHash -> IO (Maybe ModuleManifest) 31 , resolverTree :: ObjectHash -> IO (Maybe T) 32 } 33 34 filesystemResolver :: StorePath -> ObjectResolver 35 filesystemResolver store = resolver 36 where 37 resolver = ObjectResolver 38 { resolverAlias = readAlias store 39 , resolverObject = \ref -> getObject store (objectRefHash ref) 40 , resolverManifest = resolveManifestFromObjects resolver 41 , resolverTree = resolveTreeFromObjects resolver 42 } 43 44 cachedFilesystemResolver :: StorePath -> IO ObjectResolver 45 cachedFilesystemResolver store = do 46 objectCache <- newIORef Map.empty 47 manifestCache <- newIORef Map.empty 48 treeCache <- newIORef Map.empty 49 let resolver = ObjectResolver 50 { resolverAlias = readAlias store 51 , resolverObject = cachedLookup objectCache (\ref -> getObject store (objectRefHash ref)) 52 , resolverManifest = cachedLookup manifestCache (resolveManifestFromObjects resolver) 53 , resolverTree = cachedLookup treeCache (resolveTreeFromObjects resolver) 54 } 55 return resolver 56 where 57 cachedLookup :: Ord k => IORef (Map.Map k v) -> (k -> IO v) -> k -> IO v 58 cachedLookup ref load key = do 59 cache <- readIORef ref 60 case Map.lookup key cache of 61 Just value -> return value 62 Nothing -> do 63 value <- load key 64 atomicModifyIORef' ref (\m -> (Map.insert key value m, ())) 65 return value 66 67 resolveObjectByHash :: ObjectResolver -> T.Text -> ObjectHash -> IO (Maybe ByteString) 68 resolveObjectByHash resolver kind h = 69 resolverObject resolver (ObjectRef kind h) 70 71 resolveManifest :: ObjectResolver -> ObjectHash -> IO (Maybe ModuleManifest) 72 resolveManifest = resolverManifest 73 74 resolveManifestFromObjects :: ObjectResolver -> ObjectHash -> IO (Maybe ModuleManifest) 75 resolveManifestFromObjects resolver h = do 76 mBytes <- resolveObjectByHash resolver (unDomain manifestDomain) h 77 case mBytes of 78 Nothing -> return Nothing 79 Just bytes -> case decodeManifest bytes of 80 Left err -> fail $ "invalid module manifest " ++ T.unpack h ++ ": " ++ err 81 Right manifest -> return (Just manifest) 82 83 resolveTree :: ObjectResolver -> ObjectHash -> IO (Maybe T) 84 resolveTree = resolverTree 85 86 resolveTreeFromObjects :: ObjectResolver -> ObjectHash -> IO (Maybe T) 87 resolveTreeFromObjects resolver h = do 88 mNode <- resolveNode resolver h 89 case mNode of 90 Nothing -> return Nothing 91 Just node -> hydrate node 92 where 93 resolveNode r nodeHash = do 94 mBytes <- resolveObjectByHash r (unDomain merkleNodeDomain) nodeHash 95 case mBytes of 96 Nothing -> return Nothing 97 Just bytes -> return (Just (deserializeNode bytes)) 98 99 hydrate NLeaf = return (Just Research.Leaf) 100 hydrate (NStem child) = fmap Research.Stem <$> hydrateHash child 101 hydrate (NFork left right) = do 102 l <- hydrateHash left 103 r <- hydrateHash right 104 return $ Research.Fork <$> l <*> r 105 106 hydrateHash nodeHash = do 107 mChild <- resolveNode resolver nodeHash 108 case mChild of 109 Nothing -> return Nothing 110 Just child -> hydrate child