-- Licensed to the Apache Software Foundation (ASF) under one
-- or more contributor license agreements.  See the NOTICE file
-- distributed with this work for additional information
-- regarding copyright ownership.  The ASF licenses this file
-- to you under the Apache License, Version 2.0 (the
-- "License"); you may not use this file except in compliance
-- with the License.  You may obtain a copy of the License at
--
--   http://www.apache.org/licenses/LICENSE-2.0
--
-- Unless required by applicable law or agreed to in writing,
-- software distributed under the License is distributed on an
-- "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
-- KIND, either express or implied.  See the License for the
-- specific language governing permissions and limitations
-- under the License.

-- |
-- Module      : OpenDAL
-- Description : Haskell bindings for Apache OpenDAL
-- Copyright   : (c) 2023 Apache OpenDAL
-- License     : Apache-2.0
-- Maintainer  : OpenDAL Contributors <dev@opendal.apache.org>"
-- Stability   : experimental
-- Portability : non - portable (GHC extensions)
--
-- This module provides Haskell bindings for Apache OpenDAL.
module OpenDAL
  ( -- * Operator APIs

    -- ** Types
    OperatorConfig (..),
    Operator,
    Lister,
    OpenDALError (..),
    ErrorCode (..),
    EntryMode (..),
    Metadata (..),
    OperatorT (..),
    MonadOperation (..),

    -- ** Functions
    runOp,
    newOperator,

    -- * Lister APIs
    nextLister,

    -- * Operator Raw APIs
    -- $raw-operations
    readOpRaw,
    writeOpRaw,
    isExistOpRaw,
    createDirOpRaw,
    copyOpRaw,
    renameOpRaw,
    deleteOpRaw,
    statOpRaw,
    listOpRaw,
    scanOpRaw,
  )
where

import Colog (LogAction, Message, Msg (Msg), (<&))
import Control.Monad.Except (ExceptT, MonadError, MonadTrans, runExceptT, throwError)
import Control.Monad.Reader (MonadIO, MonadReader, ReaderT, ask, liftIO, runReaderT)
import Control.Monad.Trans (MonadTrans (lift))
import Data.ByteString (ByteString)
import qualified Data.ByteString as BS
import Data.HashMap.Strict (HashMap)
import qualified Data.HashMap.Strict as HashMap
import Data.String (IsString (fromString))
import Data.Text (pack)
import Data.Time (UTCTime, parseTimeM, zonedTimeToUTC)
import Data.Time.Format (defaultTimeLocale)
import Foreign
import Foreign.C.String
import GHC.Stack (emptyCallStack)
import OpenDAL.FFI

-- | `OperatorConfig` is the configuration for an `Operator`.
-- We recommend using `OverloadedStrings` to construct a default config.
--
-- For example:
--
-- default config
--
-- @
-- newOperator "memory"
-- @
--
-- custom services config
--
-- @
-- newOperator "memory" {ocConfig = HashMap.fromList [("root", "/tmp")]}
-- @
--
-- enable logging
--
-- @
-- newOperator "memory" {ocLogAction = Just simpleMessageAction}
-- @
data OperatorConfig = OperatorConfig
  { -- | The scheme of the operator. For example, "s3" or "gcs".
    OperatorConfig -> String
ocScheme :: String,
    -- | The config for the operator services. For example, "endpoint" and "access_key_id" for s3. The config is same as rust core.
    OperatorConfig -> HashMap String String
ocConfig :: HashMap String String,
    -- | The log action for the operator. If it's `Nothing`, the operator won't enable logging.
    OperatorConfig -> Maybe (LogAction IO Message)
ocLogAction :: Maybe (LogAction IO Message)
  }

instance IsString OperatorConfig where
  fromString :: String -> OperatorConfig
fromString String
s = String
-> HashMap String String
-> Maybe (LogAction IO Message)
-> OperatorConfig
OperatorConfig String
s forall k v. HashMap k v
HashMap.empty forall a. Maybe a
Nothing

-- | `Operator` is the entry for all public blocking APIs.
-- Create an `Operator` with `newOperator`.
newtype Operator = Operator (ForeignPtr RawOperator)

-- | `Lister` is designed to list entries at given path in a blocking manner.
-- Users can construct Lister by `listOp` or `scanOp`.
newtype Lister = Lister (ForeignPtr RawLister)

-- | Represents the possible error codes that can be returned by OpenDAL.
data ErrorCode
  = -- | An error occurred in the FFI layer.
    FFIError
  | -- | OpenDAL don't know what happened here, and no actions other than just returning it back. For example, s3 returns an internal service error.
    Unexpected
  | -- | Underlying service doesn't support this operation.
    Unsupported
  | -- | The config for backend is invalid.
    ConfigInvalid
  | -- | The given path is not found.
    NotFound
  | -- | The given path doesn't have enough permission for this operation.
    PermissionDenied
  | -- | The given path is a directory.
    IsADirectory
  | -- | The given path is not a directory.
    NotADirectory
  | -- | The given path already exists thus we failed to the specified operation on it.
    AlreadyExists
  | -- | Requests that sent to this path is over the limit, please slow down.
    RateLimited
  | -- | The given file paths are same.
    IsSameFile
  deriving (ErrorCode -> ErrorCode -> Bool
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
/= :: ErrorCode -> ErrorCode -> Bool
$c/= :: ErrorCode -> ErrorCode -> Bool
== :: ErrorCode -> ErrorCode -> Bool
$c== :: ErrorCode -> ErrorCode -> Bool
Eq, Int -> ErrorCode -> ShowS
[ErrorCode] -> ShowS
ErrorCode -> String
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
showList :: [ErrorCode] -> ShowS
$cshowList :: [ErrorCode] -> ShowS
show :: ErrorCode -> String
$cshow :: ErrorCode -> String
showsPrec :: Int -> ErrorCode -> ShowS
$cshowsPrec :: Int -> ErrorCode -> ShowS
Show)

-- | Represents an error that can occur when using OpenDAL.
data OpenDALError = OpenDALError
  { -- | The error code.
    OpenDALError -> ErrorCode
errorCode :: ErrorCode,
    -- | The error message.
    OpenDALError -> String
message :: String
  }
  deriving (OpenDALError -> OpenDALError -> Bool
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
/= :: OpenDALError -> OpenDALError -> Bool
$c/= :: OpenDALError -> OpenDALError -> Bool
== :: OpenDALError -> OpenDALError -> Bool
$c== :: OpenDALError -> OpenDALError -> Bool
Eq, Int -> OpenDALError -> ShowS
[OpenDALError] -> ShowS
OpenDALError -> String
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
showList :: [OpenDALError] -> ShowS
$cshowList :: [OpenDALError] -> ShowS
show :: OpenDALError -> String
$cshow :: OpenDALError -> String
showsPrec :: Int -> OpenDALError -> ShowS
$cshowsPrec :: Int -> OpenDALError -> ShowS
Show)

-- | Represents the mode of an entry in a storage system (e.g., file or directory).
data EntryMode = File | Dir | Unknown deriving (EntryMode -> EntryMode -> Bool
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
/= :: EntryMode -> EntryMode -> Bool
$c/= :: EntryMode -> EntryMode -> Bool
== :: EntryMode -> EntryMode -> Bool
$c== :: EntryMode -> EntryMode -> Bool
Eq, Int -> EntryMode -> ShowS
[EntryMode] -> ShowS
EntryMode -> String
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
showList :: [EntryMode] -> ShowS
$cshowList :: [EntryMode] -> ShowS
show :: EntryMode -> String
$cshow :: EntryMode -> String
showsPrec :: Int -> EntryMode -> ShowS
$cshowsPrec :: Int -> EntryMode -> ShowS
Show)

-- | Represents metadata for an entry in a storage system.
data Metadata = Metadata
  { -- | The mode of the entry.
    Metadata -> EntryMode
mMode :: EntryMode,
    -- | The cache control of the entry.
    Metadata -> Maybe String
mCacheControl :: Maybe String,
    -- | The content disposition of the entry.
    Metadata -> Maybe String
mContentDisposition :: Maybe String,
    -- | The content length of the entry.
    Metadata -> Integer
mContentLength :: Integer,
    -- | The content MD5 of the entry.
    Metadata -> Maybe String
mContentMD5 :: Maybe String,
    -- | The content type of the entry.
    Metadata -> Maybe String
mContentType :: Maybe String,
    -- | The ETag of the entry.
    Metadata -> Maybe String
mETag :: Maybe String,
    -- | The last modified time of the entry.
    Metadata -> Maybe UTCTime
mLastModified :: Maybe UTCTime
  }
  deriving (Metadata -> Metadata -> Bool
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
/= :: Metadata -> Metadata -> Bool
$c/= :: Metadata -> Metadata -> Bool
== :: Metadata -> Metadata -> Bool
$c== :: Metadata -> Metadata -> Bool
Eq, Int -> Metadata -> ShowS
[Metadata] -> ShowS
Metadata -> String
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
showList :: [Metadata] -> ShowS
$cshowList :: [Metadata] -> ShowS
show :: Metadata -> String
$cshow :: Metadata -> String
showsPrec :: Int -> Metadata -> ShowS
$cshowsPrec :: Int -> Metadata -> ShowS
Show)

-- | @newtype@ wrapper 'ReaderT' that keeps 'Operator' in its context.
newtype OperatorT m a = OperatorT
  {forall (m :: * -> *) a.
OperatorT m a -> ReaderT Operator (ExceptT OpenDALError m) a
runOperatorT :: ReaderT Operator (ExceptT OpenDALError m) a}
  deriving newtype (forall a b. a -> OperatorT m b -> OperatorT m a
forall a b. (a -> b) -> OperatorT m a -> OperatorT m b
forall (m :: * -> *) a b.
Functor m =>
a -> OperatorT m b -> OperatorT m a
forall (m :: * -> *) a b.
Functor m =>
(a -> b) -> OperatorT m a -> OperatorT m b
forall (f :: * -> *).
(forall a b. (a -> b) -> f a -> f b)
-> (forall a b. a -> f b -> f a) -> Functor f
<$ :: forall a b. a -> OperatorT m b -> OperatorT m a
$c<$ :: forall (m :: * -> *) a b.
Functor m =>
a -> OperatorT m b -> OperatorT m a
fmap :: forall a b. (a -> b) -> OperatorT m a -> OperatorT m b
$cfmap :: forall (m :: * -> *) a b.
Functor m =>
(a -> b) -> OperatorT m a -> OperatorT m b
Functor, forall a. a -> OperatorT m a
forall a b. OperatorT m a -> OperatorT m b -> OperatorT m a
forall a b. OperatorT m a -> OperatorT m b -> OperatorT m b
forall a b. OperatorT m (a -> b) -> OperatorT m a -> OperatorT m b
forall a b c.
(a -> b -> c) -> OperatorT m a -> OperatorT m b -> OperatorT m c
forall {m :: * -> *}. Monad m => Functor (OperatorT m)
forall (m :: * -> *) a. Monad m => a -> OperatorT m a
forall (m :: * -> *) a b.
Monad m =>
OperatorT m a -> OperatorT m b -> OperatorT m a
forall (m :: * -> *) a b.
Monad m =>
OperatorT m a -> OperatorT m b -> OperatorT m b
forall (m :: * -> *) a b.
Monad m =>
OperatorT m (a -> b) -> OperatorT m a -> OperatorT m b
forall (m :: * -> *) a b c.
Monad m =>
(a -> b -> c) -> OperatorT m a -> OperatorT m b -> OperatorT m c
forall (f :: * -> *).
Functor f
-> (forall a. a -> f a)
-> (forall a b. f (a -> b) -> f a -> f b)
-> (forall a b c. (a -> b -> c) -> f a -> f b -> f c)
-> (forall a b. f a -> f b -> f b)
-> (forall a b. f a -> f b -> f a)
-> Applicative f
<* :: forall a b. OperatorT m a -> OperatorT m b -> OperatorT m a
$c<* :: forall (m :: * -> *) a b.
Monad m =>
OperatorT m a -> OperatorT m b -> OperatorT m a
*> :: forall a b. OperatorT m a -> OperatorT m b -> OperatorT m b
$c*> :: forall (m :: * -> *) a b.
Monad m =>
OperatorT m a -> OperatorT m b -> OperatorT m b
liftA2 :: forall a b c.
(a -> b -> c) -> OperatorT m a -> OperatorT m b -> OperatorT m c
$cliftA2 :: forall (m :: * -> *) a b c.
Monad m =>
(a -> b -> c) -> OperatorT m a -> OperatorT m b -> OperatorT m c
<*> :: forall a b. OperatorT m (a -> b) -> OperatorT m a -> OperatorT m b
$c<*> :: forall (m :: * -> *) a b.
Monad m =>
OperatorT m (a -> b) -> OperatorT m a -> OperatorT m b
pure :: forall a. a -> OperatorT m a
$cpure :: forall (m :: * -> *) a. Monad m => a -> OperatorT m a
Applicative, forall a. a -> OperatorT m a
forall a b. OperatorT m a -> OperatorT m b -> OperatorT m b
forall a b. OperatorT m a -> (a -> OperatorT m b) -> OperatorT m b
forall (m :: * -> *). Monad m => Applicative (OperatorT m)
forall (m :: * -> *) a. Monad m => a -> OperatorT m a
forall (m :: * -> *) a b.
Monad m =>
OperatorT m a -> OperatorT m b -> OperatorT m b
forall (m :: * -> *) a b.
Monad m =>
OperatorT m a -> (a -> OperatorT m b) -> OperatorT m b
forall (m :: * -> *).
Applicative m
-> (forall a b. m a -> (a -> m b) -> m b)
-> (forall a b. m a -> m b -> m b)
-> (forall a. a -> m a)
-> Monad m
return :: forall a. a -> OperatorT m a
$creturn :: forall (m :: * -> *) a. Monad m => a -> OperatorT m a
>> :: forall a b. OperatorT m a -> OperatorT m b -> OperatorT m b
$c>> :: forall (m :: * -> *) a b.
Monad m =>
OperatorT m a -> OperatorT m b -> OperatorT m b
>>= :: forall a b. OperatorT m a -> (a -> OperatorT m b) -> OperatorT m b
$c>>= :: forall (m :: * -> *) a b.
Monad m =>
OperatorT m a -> (a -> OperatorT m b) -> OperatorT m b
Monad, forall a. IO a -> OperatorT m a
forall (m :: * -> *).
Monad m -> (forall a. IO a -> m a) -> MonadIO m
forall {m :: * -> *}. MonadIO m => Monad (OperatorT m)
forall (m :: * -> *) a. MonadIO m => IO a -> OperatorT m a
liftIO :: forall a. IO a -> OperatorT m a
$cliftIO :: forall (m :: * -> *) a. MonadIO m => IO a -> OperatorT m a
MonadIO, MonadReader Operator, MonadError OpenDALError)

instance MonadTrans OperatorT where
  lift :: forall (m :: * -> *) a. Monad m => m a -> OperatorT m a
lift = forall (m :: * -> *) a.
ReaderT Operator (ExceptT OpenDALError m) a -> OperatorT m a
OperatorT forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall (t :: (* -> *) -> * -> *) (m :: * -> *) a.
(MonadTrans t, Monad m) =>
m a -> t m a
lift forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall (t :: (* -> *) -> * -> *) (m :: * -> *) a.
(MonadTrans t, Monad m) =>
m a -> t m a
lift

-- | A type class for monads that can perform OpenDAL operations.
class (Monad m) => MonadOperation m where
  -- | Read the whole path into a bytes.
  readOp :: String -> m ByteString

  -- | Write bytes into given path.
  writeOp :: String -> ByteString -> m ()

  -- | Check if this path exists or not.
  isExistOp :: String -> m Bool

  -- | Create a dir at given path.
  createDirOp :: String -> m ()

  -- | Copy a file from srcPath to dstPath.
  copyOp :: String -> String -> m ()

  -- | Rename a file from srcPath to dstPath.
  renameOp :: String -> String -> m ()

  -- | Delete given path.
  deleteOp :: String -> m ()

  -- | Get given path’s metadata without cache directly.
  statOp :: String -> m Metadata

  -- | List current dir path.
  -- This function will create a new handle to list entries.
  -- An error will be returned if path doesn’t end with /.
  listOp :: String -> m Lister

  -- | List dir in flat way.
  -- Also, this function can be used to list a prefix.
  -- An error will be returned if given path doesn’t end with /.
  scanOp :: String -> m Lister

instance (MonadIO m) => MonadOperation (OperatorT m) where
  readOp :: String -> OperatorT m ByteString
readOp String
path = do
    Operator
op <- forall r (m :: * -> *). MonadReader r m => m r
ask
    Either OpenDALError ByteString
result <- forall (m :: * -> *) a. MonadIO m => IO a -> m a
liftIO forall a b. (a -> b) -> a -> b
$ Operator -> String -> IO (Either OpenDALError ByteString)
readOpRaw Operator
op String
path
    forall a c b. (a -> c) -> (b -> c) -> Either a b -> c
either forall e (m :: * -> *) a. MonadError e m => e -> m a
throwError forall (m :: * -> *) a. Monad m => a -> m a
return Either OpenDALError ByteString
result
  writeOp :: String -> ByteString -> OperatorT m ()
writeOp String
path ByteString
byte = do
    Operator
op <- forall r (m :: * -> *). MonadReader r m => m r
ask
    Either OpenDALError ()
result <- forall (m :: * -> *) a. MonadIO m => IO a -> m a
liftIO forall a b. (a -> b) -> a -> b
$ Operator -> String -> ByteString -> IO (Either OpenDALError ())
writeOpRaw Operator
op String
path ByteString
byte
    forall a c b. (a -> c) -> (b -> c) -> Either a b -> c
either forall e (m :: * -> *) a. MonadError e m => e -> m a
throwError forall (m :: * -> *) a. Monad m => a -> m a
return Either OpenDALError ()
result
  isExistOp :: String -> OperatorT m Bool
isExistOp String
path = do
    Operator
op <- forall r (m :: * -> *). MonadReader r m => m r
ask
    Either OpenDALError Bool
result <- forall (m :: * -> *) a. MonadIO m => IO a -> m a
liftIO forall a b. (a -> b) -> a -> b
$ Operator -> String -> IO (Either OpenDALError Bool)
isExistOpRaw Operator
op String
path
    forall a c b. (a -> c) -> (b -> c) -> Either a b -> c
either forall e (m :: * -> *) a. MonadError e m => e -> m a
throwError forall (m :: * -> *) a. Monad m => a -> m a
return Either OpenDALError Bool
result
  createDirOp :: String -> OperatorT m ()
createDirOp String
path = do
    Operator
op <- forall r (m :: * -> *). MonadReader r m => m r
ask
    Either OpenDALError ()
result <- forall (m :: * -> *) a. MonadIO m => IO a -> m a
liftIO forall a b. (a -> b) -> a -> b
$ Operator -> String -> IO (Either OpenDALError ())
createDirOpRaw Operator
op String
path
    forall a c b. (a -> c) -> (b -> c) -> Either a b -> c
either forall e (m :: * -> *) a. MonadError e m => e -> m a
throwError forall (m :: * -> *) a. Monad m => a -> m a
return Either OpenDALError ()
result
  copyOp :: String -> String -> OperatorT m ()
copyOp String
src String
dst = do
    Operator
op <- forall r (m :: * -> *). MonadReader r m => m r
ask
    Either OpenDALError ()
result <- forall (m :: * -> *) a. MonadIO m => IO a -> m a
liftIO forall a b. (a -> b) -> a -> b
$ Operator -> String -> String -> IO (Either OpenDALError ())
copyOpRaw Operator
op String
src String
dst
    forall a c b. (a -> c) -> (b -> c) -> Either a b -> c
either forall e (m :: * -> *) a. MonadError e m => e -> m a
throwError forall (m :: * -> *) a. Monad m => a -> m a
return Either OpenDALError ()
result
  renameOp :: String -> String -> OperatorT m ()
renameOp String
src String
dst = do
    Operator
op <- forall r (m :: * -> *). MonadReader r m => m r
ask
    Either OpenDALError ()
result <- forall (m :: * -> *) a. MonadIO m => IO a -> m a
liftIO forall a b. (a -> b) -> a -> b
$ Operator -> String -> String -> IO (Either OpenDALError ())
renameOpRaw Operator
op String
src String
dst
    forall a c b. (a -> c) -> (b -> c) -> Either a b -> c
either forall e (m :: * -> *) a. MonadError e m => e -> m a
throwError forall (m :: * -> *) a. Monad m => a -> m a
return Either OpenDALError ()
result
  deleteOp :: String -> OperatorT m ()
deleteOp String
path = do
    Operator
op <- forall r (m :: * -> *). MonadReader r m => m r
ask
    Either OpenDALError ()
result <- forall (m :: * -> *) a. MonadIO m => IO a -> m a
liftIO forall a b. (a -> b) -> a -> b
$ Operator -> String -> IO (Either OpenDALError ())
deleteOpRaw Operator
op String
path
    forall a c b. (a -> c) -> (b -> c) -> Either a b -> c
either forall e (m :: * -> *) a. MonadError e m => e -> m a
throwError forall (m :: * -> *) a. Monad m => a -> m a
return Either OpenDALError ()
result
  statOp :: String -> OperatorT m Metadata
statOp String
path = do
    Operator
op <- forall r (m :: * -> *). MonadReader r m => m r
ask
    Either OpenDALError Metadata
result <- forall (m :: * -> *) a. MonadIO m => IO a -> m a
liftIO forall a b. (a -> b) -> a -> b
$ Operator -> String -> IO (Either OpenDALError Metadata)
statOpRaw Operator
op String
path
    forall a c b. (a -> c) -> (b -> c) -> Either a b -> c
either forall e (m :: * -> *) a. MonadError e m => e -> m a
throwError forall (m :: * -> *) a. Monad m => a -> m a
return Either OpenDALError Metadata
result
  listOp :: String -> OperatorT m Lister
listOp String
path = do
    Operator
op <- forall r (m :: * -> *). MonadReader r m => m r
ask
    Either OpenDALError Lister
result <- forall (m :: * -> *) a. MonadIO m => IO a -> m a
liftIO forall a b. (a -> b) -> a -> b
$ Operator -> String -> IO (Either OpenDALError Lister)
listOpRaw Operator
op String
path
    forall a c b. (a -> c) -> (b -> c) -> Either a b -> c
either forall e (m :: * -> *) a. MonadError e m => e -> m a
throwError forall (m :: * -> *) a. Monad m => a -> m a
return Either OpenDALError Lister
result
  scanOp :: String -> OperatorT m Lister
scanOp String
path = do
    Operator
op <- forall r (m :: * -> *). MonadReader r m => m r
ask
    Either OpenDALError Lister
result <- forall (m :: * -> *) a. MonadIO m => IO a -> m a
liftIO forall a b. (a -> b) -> a -> b
$ Operator -> String -> IO (Either OpenDALError Lister)
scanOpRaw Operator
op String
path
    forall a c b. (a -> c) -> (b -> c) -> Either a b -> c
either forall e (m :: * -> *) a. MonadError e m => e -> m a
throwError forall (m :: * -> *) a. Monad m => a -> m a
return Either OpenDALError Lister
result

-- helper functions

byteSliceToByteString :: ByteSlice -> IO ByteString
byteSliceToByteString :: ByteSlice -> IO ByteString
byteSliceToByteString (ByteSlice CString
bsDataPtr CSize
len) = CStringLen -> IO ByteString
BS.packCStringLen (CString
bsDataPtr, forall a b. (Integral a, Num b) => a -> b
fromIntegral CSize
len)

parseErrorCode :: Int -> ErrorCode
parseErrorCode :: Int -> ErrorCode
parseErrorCode Int
1 = ErrorCode
FFIError
parseErrorCode Int
2 = ErrorCode
Unexpected
parseErrorCode Int
3 = ErrorCode
Unsupported
parseErrorCode Int
4 = ErrorCode
ConfigInvalid
parseErrorCode Int
5 = ErrorCode
NotFound
parseErrorCode Int
6 = ErrorCode
PermissionDenied
parseErrorCode Int
7 = ErrorCode
IsADirectory
parseErrorCode Int
8 = ErrorCode
NotADirectory
parseErrorCode Int
9 = ErrorCode
AlreadyExists
parseErrorCode Int
10 = ErrorCode
RateLimited
parseErrorCode Int
11 = ErrorCode
IsSameFile
parseErrorCode Int
_ = ErrorCode
FFIError

parseEntryMode :: Int -> EntryMode
parseEntryMode :: Int -> EntryMode
parseEntryMode Int
0 = EntryMode
File
parseEntryMode Int
1 = EntryMode
Dir
parseEntryMode Int
_ = EntryMode
Unknown

parseCString :: CString -> IO (Maybe String)
parseCString :: CString -> IO (Maybe String)
parseCString CString
value | CString
value forall a. Eq a => a -> a -> Bool
== forall a. Ptr a
nullPtr = forall (m :: * -> *) a. Monad m => a -> m a
return forall a. Maybe a
Nothing
parseCString CString
value = do
  String
value' <- CString -> IO String
peekCString CString
value
  forall a. Ptr a -> IO ()
free CString
value
  forall (m :: * -> *) a. Monad m => a -> m a
return forall a b. (a -> b) -> a -> b
$ forall a. a -> Maybe a
Just String
value'

parseTime :: String -> Maybe UTCTime
parseTime :: String -> Maybe UTCTime
parseTime String
time = ZonedTime -> UTCTime
zonedTimeToUTC forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> forall (m :: * -> *) t.
(MonadFail m, ParseTime t) =>
Bool -> TimeLocale -> String -> String -> m t
parseTimeM Bool
True TimeLocale
defaultTimeLocale String
"%Y-%m-%dT%H:%M:%S%Q%z" String
time

parseFFIMetadata :: FFIMetadata -> IO Metadata
parseFFIMetadata :: FFIMetadata -> IO Metadata
parseFFIMetadata (FFIMetadata CUInt
mode CString
cacheControl CString
contentDisposition CULong
contentLength CString
contentMD5 CString
contentType CString
eTag CString
lastModified) = do
  let mode' :: EntryMode
mode' = Int -> EntryMode
parseEntryMode forall a b. (a -> b) -> a -> b
$ forall a b. (Integral a, Num b) => a -> b
fromIntegral CUInt
mode
  Maybe String
cacheControl' <- CString -> IO (Maybe String)
parseCString CString
cacheControl
  Maybe String
contentDisposition' <- CString -> IO (Maybe String)
parseCString CString
contentDisposition
  let contentLength' :: Integer
contentLength' = forall a. Integral a => a -> Integer
toInteger CULong
contentLength
  Maybe String
contentMD5' <- CString -> IO (Maybe String)
parseCString CString
contentMD5
  Maybe String
contentType' <- CString -> IO (Maybe String)
parseCString CString
contentType
  Maybe String
eTag' <- CString -> IO (Maybe String)
parseCString CString
eTag
  Maybe UTCTime
lastModified' <- (forall (m :: * -> *) a b. Monad m => m a -> (a -> m b) -> m b
>>= String -> Maybe UTCTime
parseTime) forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> CString -> IO (Maybe String)
parseCString CString
lastModified
  forall (m :: * -> *) a. Monad m => a -> m a
return forall a b. (a -> b) -> a -> b
$
    Metadata
      { mMode :: EntryMode
mMode = EntryMode
mode',
        mCacheControl :: Maybe String
mCacheControl = Maybe String
cacheControl',
        mContentDisposition :: Maybe String
mContentDisposition = Maybe String
contentDisposition',
        mContentLength :: Integer
mContentLength = Integer
contentLength',
        mContentMD5 :: Maybe String
mContentMD5 = Maybe String
contentMD5',
        mContentType :: Maybe String
mContentType = Maybe String
contentType',
        mETag :: Maybe String
mETag = Maybe String
eTag',
        mLastModified :: Maybe UTCTime
mLastModified = Maybe UTCTime
lastModified'
      }

-- Exported functions

-- |  Runner for 'OperatorT' monad.
-- This function will run given 'OperatorT' monad with given 'Operator'.
--
-- Let's see an example:
--
-- @
-- operation :: MonadOperation m => m ()
-- operation = __do__
--    writeOp op "key1" "value1"
--    writeOp op "key2" "value2"
--    value1 <- readOp op "key1"
--    value2 <- readOp op "key2"
-- @
--
-- You can run this operation with 'runOp' function:
--
-- @
-- runOp operator operation
-- @
runOp :: Operator -> OperatorT m a -> m (Either OpenDALError a)
runOp :: forall (m :: * -> *) a.
Operator -> OperatorT m a -> m (Either OpenDALError a)
runOp Operator
op = forall e (m :: * -> *) a. ExceptT e m a -> m (Either e a)
runExceptT forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall a b c. (a -> b -> c) -> b -> a -> c
flip forall r (m :: * -> *) a. ReaderT r m a -> r -> m a
runReaderT Operator
op forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall (m :: * -> *) a.
OperatorT m a -> ReaderT Operator (ExceptT OpenDALError m) a
runOperatorT
{-# INLINE runOp #-}

-- | Creates a new OpenDAL operator via `OperatorConfig`.
newOperator :: OperatorConfig -> IO (Either OpenDALError Operator)
newOperator :: OperatorConfig -> IO (Either OpenDALError Operator)
newOperator (OperatorConfig String
scheme HashMap String String
hashMap Maybe (LogAction IO Message)
maybeLogger) = do
  let keysAndValues :: [(String, String)]
keysAndValues = forall k v. HashMap k v -> [(k, v)]
HashMap.toList HashMap String String
hashMap
  forall a. String -> (CString -> IO a) -> IO a
withCString String
scheme forall a b. (a -> b) -> a -> b
$ \CString
cScheme ->
    forall a b res.
(a -> (b -> res) -> res) -> [a] -> ([b] -> res) -> res
withMany forall a. String -> (CString -> IO a) -> IO a
withCString (forall a b. (a -> b) -> [a] -> [b]
map forall a b. (a, b) -> a
fst [(String, String)]
keysAndValues) forall a b. (a -> b) -> a -> b
$ \[CString]
cKeys ->
      forall a b res.
(a -> (b -> res) -> res) -> [a] -> ([b] -> res) -> res
withMany forall a. String -> (CString -> IO a) -> IO a
withCString (forall a b. (a -> b) -> [a] -> [b]
map forall a b. (a, b) -> b
snd [(String, String)]
keysAndValues) forall a b. (a -> b) -> a -> b
$ \[CString]
cValues ->
        forall a b. Storable a => Int -> (Ptr a -> IO b) -> IO b
allocaArray (forall (t :: * -> *) a. Foldable t => t a -> Int
length [(String, String)]
keysAndValues) forall a b. (a -> b) -> a -> b
$ \Ptr CString
cKeysPtr ->
          forall a b. Storable a => Int -> (Ptr a -> IO b) -> IO b
allocaArray (forall (t :: * -> *) a. Foldable t => t a -> Int
length [(String, String)]
keysAndValues) forall a b. (a -> b) -> a -> b
$ \Ptr CString
cValuesPtr ->
            forall a b. Storable a => (Ptr a -> IO b) -> IO b
alloca forall a b. (a -> b) -> a -> b
$ \Ptr (FFIResult RawOperator)
ffiResultPtr -> do
              FunPtr (CUInt -> CString -> IO ())
logFnPtr <- case Maybe (LogAction IO Message)
maybeLogger of
                Just LogAction IO Message
logger -> (CUInt -> CString -> IO ())
-> IO (FunPtr (CUInt -> CString -> IO ()))
wrapLogFn (forall {a} {sev}.
(Integral a, Enum sev) =>
LogAction IO (Msg sev) -> a -> CString -> IO ()
logFn LogAction IO Message
logger)
                Maybe (LogAction IO Message)
Nothing -> forall (m :: * -> *) a. Monad m => a -> m a
return forall a. FunPtr a
nullFunPtr
              forall a. Storable a => Ptr a -> [a] -> IO ()
pokeArray Ptr CString
cKeysPtr [CString]
cKeys
              forall a. Storable a => Ptr a -> [a] -> IO ()
pokeArray Ptr CString
cValuesPtr [CString]
cValues
              CString
-> Ptr CString
-> Ptr CString
-> CSize
-> FunPtr (CUInt -> CString -> IO ())
-> Ptr (FFIResult RawOperator)
-> IO ()
c_via_map_ffi CString
cScheme Ptr CString
cKeysPtr Ptr CString
cValuesPtr (forall a b. (Integral a, Num b) => a -> b
fromIntegral forall a b. (a -> b) -> a -> b
$ forall (t :: * -> *) a. Foldable t => t a -> Int
length [(String, String)]
keysAndValues) FunPtr (CUInt -> CString -> IO ())
logFnPtr Ptr (FFIResult RawOperator)
ffiResultPtr
              FFIResult RawOperator
ffiResult <- forall a. Storable a => Ptr a -> IO a
peek Ptr (FFIResult RawOperator)
ffiResultPtr
              if forall a. FFIResult a -> CUInt
ffiCode FFIResult RawOperator
ffiResult forall a. Eq a => a -> a -> Bool
== CUInt
0
                then do
                  Operator
op <- ForeignPtr RawOperator -> Operator
Operator forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> forall a. FinalizerPtr a -> Ptr a -> IO (ForeignPtr a)
newForeignPtr FunPtr (Ptr RawOperator -> IO ())
c_free_operator (forall a. FFIResult a -> Ptr a
dataPtr FFIResult RawOperator
ffiResult)
                  forall (m :: * -> *) a. Monad m => a -> m a
return forall a b. (a -> b) -> a -> b
$ forall a b. b -> Either a b
Right Operator
op
                else do
                  let code :: ErrorCode
code = Int -> ErrorCode
parseErrorCode forall a b. (a -> b) -> a -> b
$ forall a b. (Integral a, Num b) => a -> b
fromIntegral forall a b. (a -> b) -> a -> b
$ forall a. FFIResult a -> CUInt
ffiCode FFIResult RawOperator
ffiResult
                  String
errMsg <- CString -> IO String
peekCString (forall a. FFIResult a -> CString
errorMessage FFIResult RawOperator
ffiResult)
                  forall (m :: * -> *) a. Monad m => a -> m a
return forall a b. (a -> b) -> a -> b
$ forall a b. a -> Either a b
Left forall a b. (a -> b) -> a -> b
$ ErrorCode -> String -> OpenDALError
OpenDALError ErrorCode
code String
errMsg
  where
    logFn :: LogAction IO (Msg sev) -> a -> CString -> IO ()
logFn LogAction IO (Msg sev)
logger a
enumSeverity CString
cStr = do
      String
str <- CString -> IO String
peekCString CString
cStr
      LogAction IO (Msg sev)
logger forall (m :: * -> *) msg. LogAction m msg -> msg -> m ()
<& forall sev. sev -> CallStack -> Text -> Msg sev
Msg (forall a. Enum a => Int -> a
toEnum (forall a b. (Integral a, Num b) => a -> b
fromIntegral a
enumSeverity)) CallStack
emptyCallStack (String -> Text
pack String
str)

-- $raw-operations
-- Functions for performing raw OpenDAL operations are defined below.
-- These functions are not meant to be used directly in most cases.
-- Instead, use the high-level interface provided by the 'MonadOperation' type class.

-- | Read the whole path into a bytes.
readOpRaw :: Operator -> String -> IO (Either OpenDALError ByteString)
readOpRaw :: Operator -> String -> IO (Either OpenDALError ByteString)
readOpRaw (Operator ForeignPtr RawOperator
op) String
path = forall a b. ForeignPtr a -> (Ptr a -> IO b) -> IO b
withForeignPtr ForeignPtr RawOperator
op forall a b. (a -> b) -> a -> b
$ \Ptr RawOperator
opptr ->
  forall a. String -> (CString -> IO a) -> IO a
withCString String
path forall a b. (a -> b) -> a -> b
$ \CString
cPath ->
    forall a b. Storable a => (Ptr a -> IO b) -> IO b
alloca forall a b. (a -> b) -> a -> b
$ \Ptr (FFIResult ByteSlice)
ffiResultPtr -> do
      Ptr RawOperator -> CString -> Ptr (FFIResult ByteSlice) -> IO ()
c_blocking_read Ptr RawOperator
opptr CString
cPath Ptr (FFIResult ByteSlice)
ffiResultPtr
      FFIResult ByteSlice
ffiResult <- forall a. Storable a => Ptr a -> IO a
peek Ptr (FFIResult ByteSlice)
ffiResultPtr
      if forall a. FFIResult a -> CUInt
ffiCode FFIResult ByteSlice
ffiResult forall a. Eq a => a -> a -> Bool
== CUInt
0
        then do
          ByteSlice
byteslice <- forall a. Storable a => Ptr a -> IO a
peek forall a b. (a -> b) -> a -> b
$ forall a. FFIResult a -> Ptr a
dataPtr FFIResult ByteSlice
ffiResult
          ByteString
byte <- ByteSlice -> IO ByteString
byteSliceToByteString ByteSlice
byteslice
          CString -> CSize -> IO ()
c_free_byteslice (ByteSlice -> CString
bsData ByteSlice
byteslice) (ByteSlice -> CSize
bsLen ByteSlice
byteslice)
          forall (m :: * -> *) a. Monad m => a -> m a
return forall a b. (a -> b) -> a -> b
$ forall a b. b -> Either a b
Right ByteString
byte
        else do
          let code :: ErrorCode
code = Int -> ErrorCode
parseErrorCode forall a b. (a -> b) -> a -> b
$ forall a b. (Integral a, Num b) => a -> b
fromIntegral forall a b. (a -> b) -> a -> b
$ forall a. FFIResult a -> CUInt
ffiCode FFIResult ByteSlice
ffiResult
          String
errMsg <- CString -> IO String
peekCString (forall a. FFIResult a -> CString
errorMessage FFIResult ByteSlice
ffiResult)
          forall (m :: * -> *) a. Monad m => a -> m a
return forall a b. (a -> b) -> a -> b
$ forall a b. a -> Either a b
Left forall a b. (a -> b) -> a -> b
$ ErrorCode -> String -> OpenDALError
OpenDALError ErrorCode
code String
errMsg

-- | Write bytes into given path.
writeOpRaw :: Operator -> String -> ByteString -> IO (Either OpenDALError ())
writeOpRaw :: Operator -> String -> ByteString -> IO (Either OpenDALError ())
writeOpRaw (Operator ForeignPtr RawOperator
op) String
path ByteString
byte = forall a b. ForeignPtr a -> (Ptr a -> IO b) -> IO b
withForeignPtr ForeignPtr RawOperator
op forall a b. (a -> b) -> a -> b
$ \Ptr RawOperator
opptr ->
  forall a. String -> (CString -> IO a) -> IO a
withCString String
path forall a b. (a -> b) -> a -> b
$ \CString
cPath ->
    forall a. ByteString -> (CStringLen -> IO a) -> IO a
BS.useAsCStringLen ByteString
byte forall a b. (a -> b) -> a -> b
$ \(CString
cByte, Int
len) ->
      forall a b. Storable a => (Ptr a -> IO b) -> IO b
alloca forall a b. (a -> b) -> a -> b
$ \Ptr (FFIResult ())
ffiResultPtr -> do
        Ptr RawOperator
-> CString -> CString -> CSize -> Ptr (FFIResult ()) -> IO ()
c_blocking_write Ptr RawOperator
opptr CString
cPath CString
cByte (forall a b. (Integral a, Num b) => a -> b
fromIntegral Int
len) Ptr (FFIResult ())
ffiResultPtr
        FFIResult ()
ffiResult <- forall a. Storable a => Ptr a -> IO a
peek Ptr (FFIResult ())
ffiResultPtr
        if forall a. FFIResult a -> CUInt
ffiCode FFIResult ()
ffiResult forall a. Eq a => a -> a -> Bool
== CUInt
0
          then forall (m :: * -> *) a. Monad m => a -> m a
return forall a b. (a -> b) -> a -> b
$ forall a b. b -> Either a b
Right ()
          else do
            let code :: ErrorCode
code = Int -> ErrorCode
parseErrorCode forall a b. (a -> b) -> a -> b
$ forall a b. (Integral a, Num b) => a -> b
fromIntegral forall a b. (a -> b) -> a -> b
$ forall a. FFIResult a -> CUInt
ffiCode FFIResult ()
ffiResult
            String
errMsg <- CString -> IO String
peekCString (forall a. FFIResult a -> CString
errorMessage FFIResult ()
ffiResult)
            forall (m :: * -> *) a. Monad m => a -> m a
return forall a b. (a -> b) -> a -> b
$ forall a b. a -> Either a b
Left forall a b. (a -> b) -> a -> b
$ ErrorCode -> String -> OpenDALError
OpenDALError ErrorCode
code String
errMsg

-- | Check if this path exists or not.
isExistOpRaw :: Operator -> String -> IO (Either OpenDALError Bool)
isExistOpRaw :: Operator -> String -> IO (Either OpenDALError Bool)
isExistOpRaw (Operator ForeignPtr RawOperator
op) String
path = forall a b. ForeignPtr a -> (Ptr a -> IO b) -> IO b
withForeignPtr ForeignPtr RawOperator
op forall a b. (a -> b) -> a -> b
$ \Ptr RawOperator
opptr ->
  forall a. String -> (CString -> IO a) -> IO a
withCString String
path forall a b. (a -> b) -> a -> b
$ \CString
cPath ->
    forall a b. Storable a => (Ptr a -> IO b) -> IO b
alloca forall a b. (a -> b) -> a -> b
$ \Ptr (FFIResult CBool)
ffiResultPtr -> do
      Ptr RawOperator -> CString -> Ptr (FFIResult CBool) -> IO ()
c_blocking_is_exist Ptr RawOperator
opptr CString
cPath Ptr (FFIResult CBool)
ffiResultPtr
      FFIResult CBool
ffiResult <- forall a. Storable a => Ptr a -> IO a
peek Ptr (FFIResult CBool)
ffiResultPtr
      if forall a. FFIResult a -> CUInt
ffiCode FFIResult CBool
ffiResult forall a. Eq a => a -> a -> Bool
== CUInt
0
        then do
          CBool
val <- forall a. Storable a => Ptr a -> IO a
peek forall a b. (a -> b) -> a -> b
$ forall a. FFIResult a -> Ptr a
dataPtr FFIResult CBool
ffiResult
          let isExist :: Bool
isExist = CBool
val forall a. Eq a => a -> a -> Bool
/= CBool
0
          forall (m :: * -> *) a. Monad m => a -> m a
return forall a b. (a -> b) -> a -> b
$ forall a b. b -> Either a b
Right Bool
isExist
        else do
          let code :: ErrorCode
code = Int -> ErrorCode
parseErrorCode forall a b. (a -> b) -> a -> b
$ forall a b. (Integral a, Num b) => a -> b
fromIntegral forall a b. (a -> b) -> a -> b
$ forall a. FFIResult a -> CUInt
ffiCode FFIResult CBool
ffiResult
          String
errMsg <- CString -> IO String
peekCString (forall a. FFIResult a -> CString
errorMessage FFIResult CBool
ffiResult)
          forall (m :: * -> *) a. Monad m => a -> m a
return forall a b. (a -> b) -> a -> b
$ forall a b. a -> Either a b
Left forall a b. (a -> b) -> a -> b
$ ErrorCode -> String -> OpenDALError
OpenDALError ErrorCode
code String
errMsg

-- | Create a dir at given path.
createDirOpRaw :: Operator -> String -> IO (Either OpenDALError ())
createDirOpRaw :: Operator -> String -> IO (Either OpenDALError ())
createDirOpRaw (Operator ForeignPtr RawOperator
op) String
path = forall a b. ForeignPtr a -> (Ptr a -> IO b) -> IO b
withForeignPtr ForeignPtr RawOperator
op forall a b. (a -> b) -> a -> b
$ \Ptr RawOperator
opptr ->
  forall a. String -> (CString -> IO a) -> IO a
withCString String
path forall a b. (a -> b) -> a -> b
$ \CString
cPath ->
    forall a b. Storable a => (Ptr a -> IO b) -> IO b
alloca forall a b. (a -> b) -> a -> b
$ \Ptr (FFIResult ())
ffiResultPtr -> do
      Ptr RawOperator -> CString -> Ptr (FFIResult ()) -> IO ()
c_blocking_create_dir Ptr RawOperator
opptr CString
cPath Ptr (FFIResult ())
ffiResultPtr
      FFIResult ()
ffiResult <- forall a. Storable a => Ptr a -> IO a
peek Ptr (FFIResult ())
ffiResultPtr
      if forall a. FFIResult a -> CUInt
ffiCode FFIResult ()
ffiResult forall a. Eq a => a -> a -> Bool
== CUInt
0
        then forall (m :: * -> *) a. Monad m => a -> m a
return forall a b. (a -> b) -> a -> b
$ forall a b. b -> Either a b
Right ()
        else do
          let code :: ErrorCode
code = Int -> ErrorCode
parseErrorCode forall a b. (a -> b) -> a -> b
$ forall a b. (Integral a, Num b) => a -> b
fromIntegral forall a b. (a -> b) -> a -> b
$ forall a. FFIResult a -> CUInt
ffiCode FFIResult ()
ffiResult
          String
errMsg <- CString -> IO String
peekCString (forall a. FFIResult a -> CString
errorMessage FFIResult ()
ffiResult)
          forall (m :: * -> *) a. Monad m => a -> m a
return forall a b. (a -> b) -> a -> b
$ forall a b. a -> Either a b
Left forall a b. (a -> b) -> a -> b
$ ErrorCode -> String -> OpenDALError
OpenDALError ErrorCode
code String
errMsg

-- | Copy a file from srcPath to dstPath.
copyOpRaw :: Operator -> String -> String -> IO (Either OpenDALError ())
copyOpRaw :: Operator -> String -> String -> IO (Either OpenDALError ())
copyOpRaw (Operator ForeignPtr RawOperator
op) String
srcPath String
dstPath = forall a b. ForeignPtr a -> (Ptr a -> IO b) -> IO b
withForeignPtr ForeignPtr RawOperator
op forall a b. (a -> b) -> a -> b
$ \Ptr RawOperator
opptr ->
  forall a. String -> (CString -> IO a) -> IO a
withCString String
srcPath forall a b. (a -> b) -> a -> b
$ \CString
cSrcPath ->
    forall a. String -> (CString -> IO a) -> IO a
withCString String
dstPath forall a b. (a -> b) -> a -> b
$ \CString
cDstPath ->
      forall a b. Storable a => (Ptr a -> IO b) -> IO b
alloca forall a b. (a -> b) -> a -> b
$ \Ptr (FFIResult ())
ffiResultPtr -> do
        Ptr RawOperator
-> CString -> CString -> Ptr (FFIResult ()) -> IO ()
c_blocking_copy Ptr RawOperator
opptr CString
cSrcPath CString
cDstPath Ptr (FFIResult ())
ffiResultPtr
        FFIResult ()
ffiResult <- forall a. Storable a => Ptr a -> IO a
peek Ptr (FFIResult ())
ffiResultPtr
        if forall a. FFIResult a -> CUInt
ffiCode FFIResult ()
ffiResult forall a. Eq a => a -> a -> Bool
== CUInt
0
          then forall (m :: * -> *) a. Monad m => a -> m a
return forall a b. (a -> b) -> a -> b
$ forall a b. b -> Either a b
Right ()
          else do
            let code :: ErrorCode
code = Int -> ErrorCode
parseErrorCode forall a b. (a -> b) -> a -> b
$ forall a b. (Integral a, Num b) => a -> b
fromIntegral forall a b. (a -> b) -> a -> b
$ forall a. FFIResult a -> CUInt
ffiCode FFIResult ()
ffiResult
            String
errMsg <- CString -> IO String
peekCString (forall a. FFIResult a -> CString
errorMessage FFIResult ()
ffiResult)
            forall (m :: * -> *) a. Monad m => a -> m a
return forall a b. (a -> b) -> a -> b
$ forall a b. a -> Either a b
Left forall a b. (a -> b) -> a -> b
$ ErrorCode -> String -> OpenDALError
OpenDALError ErrorCode
code String
errMsg

-- | Rename a file from srcPath to dstPath.
renameOpRaw :: Operator -> String -> String -> IO (Either OpenDALError ())
renameOpRaw :: Operator -> String -> String -> IO (Either OpenDALError ())
renameOpRaw (Operator ForeignPtr RawOperator
op) String
srcPath String
dstPath = forall a b. ForeignPtr a -> (Ptr a -> IO b) -> IO b
withForeignPtr ForeignPtr RawOperator
op forall a b. (a -> b) -> a -> b
$ \Ptr RawOperator
opptr ->
  forall a. String -> (CString -> IO a) -> IO a
withCString String
srcPath forall a b. (a -> b) -> a -> b
$ \CString
cSrcPath ->
    forall a. String -> (CString -> IO a) -> IO a
withCString String
dstPath forall a b. (a -> b) -> a -> b
$ \CString
cDstPath ->
      forall a b. Storable a => (Ptr a -> IO b) -> IO b
alloca forall a b. (a -> b) -> a -> b
$ \Ptr (FFIResult ())
ffiResultPtr -> do
        Ptr RawOperator
-> CString -> CString -> Ptr (FFIResult ()) -> IO ()
c_blocking_rename Ptr RawOperator
opptr CString
cSrcPath CString
cDstPath Ptr (FFIResult ())
ffiResultPtr
        FFIResult ()
ffiResult <- forall a. Storable a => Ptr a -> IO a
peek Ptr (FFIResult ())
ffiResultPtr
        if forall a. FFIResult a -> CUInt
ffiCode FFIResult ()
ffiResult forall a. Eq a => a -> a -> Bool
== CUInt
0
          then forall (m :: * -> *) a. Monad m => a -> m a
return forall a b. (a -> b) -> a -> b
$ forall a b. b -> Either a b
Right ()
          else do
            let code :: ErrorCode
code = Int -> ErrorCode
parseErrorCode forall a b. (a -> b) -> a -> b
$ forall a b. (Integral a, Num b) => a -> b
fromIntegral forall a b. (a -> b) -> a -> b
$ forall a. FFIResult a -> CUInt
ffiCode FFIResult ()
ffiResult
            String
errMsg <- CString -> IO String
peekCString (forall a. FFIResult a -> CString
errorMessage FFIResult ()
ffiResult)
            forall (m :: * -> *) a. Monad m => a -> m a
return forall a b. (a -> b) -> a -> b
$ forall a b. a -> Either a b
Left forall a b. (a -> b) -> a -> b
$ ErrorCode -> String -> OpenDALError
OpenDALError ErrorCode
code String
errMsg

-- | Delete given path.
deleteOpRaw :: Operator -> String -> IO (Either OpenDALError ())
deleteOpRaw :: Operator -> String -> IO (Either OpenDALError ())
deleteOpRaw (Operator ForeignPtr RawOperator
op) String
path = forall a b. ForeignPtr a -> (Ptr a -> IO b) -> IO b
withForeignPtr ForeignPtr RawOperator
op forall a b. (a -> b) -> a -> b
$ \Ptr RawOperator
opptr ->
  forall a. String -> (CString -> IO a) -> IO a
withCString String
path forall a b. (a -> b) -> a -> b
$ \CString
cPath ->
    forall a b. Storable a => (Ptr a -> IO b) -> IO b
alloca forall a b. (a -> b) -> a -> b
$ \Ptr (FFIResult ())
ffiResultPtr -> do
      Ptr RawOperator -> CString -> Ptr (FFIResult ()) -> IO ()
c_blocking_delete Ptr RawOperator
opptr CString
cPath Ptr (FFIResult ())
ffiResultPtr
      FFIResult ()
ffiResult <- forall a. Storable a => Ptr a -> IO a
peek Ptr (FFIResult ())
ffiResultPtr
      if forall a. FFIResult a -> CUInt
ffiCode FFIResult ()
ffiResult forall a. Eq a => a -> a -> Bool
== CUInt
0
        then forall (m :: * -> *) a. Monad m => a -> m a
return forall a b. (a -> b) -> a -> b
$ forall a b. b -> Either a b
Right ()
        else do
          let code :: ErrorCode
code = Int -> ErrorCode
parseErrorCode forall a b. (a -> b) -> a -> b
$ forall a b. (Integral a, Num b) => a -> b
fromIntegral forall a b. (a -> b) -> a -> b
$ forall a. FFIResult a -> CUInt
ffiCode FFIResult ()
ffiResult
          String
errMsg <- CString -> IO String
peekCString (forall a. FFIResult a -> CString
errorMessage FFIResult ()
ffiResult)
          forall (m :: * -> *) a. Monad m => a -> m a
return forall a b. (a -> b) -> a -> b
$ forall a b. a -> Either a b
Left forall a b. (a -> b) -> a -> b
$ ErrorCode -> String -> OpenDALError
OpenDALError ErrorCode
code String
errMsg

-- | Get given path’s metadata without cache directly.
statOpRaw :: Operator -> String -> IO (Either OpenDALError Metadata)
statOpRaw :: Operator -> String -> IO (Either OpenDALError Metadata)
statOpRaw (Operator ForeignPtr RawOperator
op) String
path = forall a b. ForeignPtr a -> (Ptr a -> IO b) -> IO b
withForeignPtr ForeignPtr RawOperator
op forall a b. (a -> b) -> a -> b
$ \Ptr RawOperator
opptr ->
  forall a. String -> (CString -> IO a) -> IO a
withCString String
path forall a b. (a -> b) -> a -> b
$ \CString
cPath ->
    forall a b. Storable a => (Ptr a -> IO b) -> IO b
alloca forall a b. (a -> b) -> a -> b
$ \Ptr (FFIResult FFIMetadata)
ffiResultPtr -> do
      Ptr RawOperator -> CString -> Ptr (FFIResult FFIMetadata) -> IO ()
c_blocking_stat Ptr RawOperator
opptr CString
cPath Ptr (FFIResult FFIMetadata)
ffiResultPtr
      FFIResult FFIMetadata
ffiResult <- forall a. Storable a => Ptr a -> IO a
peek Ptr (FFIResult FFIMetadata)
ffiResultPtr
      if forall a. FFIResult a -> CUInt
ffiCode FFIResult FFIMetadata
ffiResult forall a. Eq a => a -> a -> Bool
== CUInt
0
        then do
          FFIMetadata
ffimatadata <- forall a. Storable a => Ptr a -> IO a
peek forall a b. (a -> b) -> a -> b
$ forall a. FFIResult a -> Ptr a
dataPtr FFIResult FFIMetadata
ffiResult
          Metadata
metadata <- FFIMetadata -> IO Metadata
parseFFIMetadata FFIMetadata
ffimatadata
          forall (m :: * -> *) a. Monad m => a -> m a
return forall a b. (a -> b) -> a -> b
$ forall a b. b -> Either a b
Right Metadata
metadata
        else do
          let code :: ErrorCode
code = Int -> ErrorCode
parseErrorCode forall a b. (a -> b) -> a -> b
$ forall a b. (Integral a, Num b) => a -> b
fromIntegral forall a b. (a -> b) -> a -> b
$ forall a. FFIResult a -> CUInt
ffiCode FFIResult FFIMetadata
ffiResult
          String
errMsg <- CString -> IO String
peekCString (forall a. FFIResult a -> CString
errorMessage FFIResult FFIMetadata
ffiResult)
          forall (m :: * -> *) a. Monad m => a -> m a
return forall a b. (a -> b) -> a -> b
$ forall a b. a -> Either a b
Left forall a b. (a -> b) -> a -> b
$ ErrorCode -> String -> OpenDALError
OpenDALError ErrorCode
code String
errMsg

-- | List current dir path.
-- This function will create a new handle to list entries.
-- An error will be returned if path doesn’t end with /.
listOpRaw :: Operator -> String -> IO (Either OpenDALError Lister)
listOpRaw :: Operator -> String -> IO (Either OpenDALError Lister)
listOpRaw (Operator ForeignPtr RawOperator
op) String
path = forall a b. ForeignPtr a -> (Ptr a -> IO b) -> IO b
withForeignPtr ForeignPtr RawOperator
op forall a b. (a -> b) -> a -> b
$ \Ptr RawOperator
opptr ->
  forall a. String -> (CString -> IO a) -> IO a
withCString String
path forall a b. (a -> b) -> a -> b
$ \CString
cPath ->
    forall a b. Storable a => (Ptr a -> IO b) -> IO b
alloca forall a b. (a -> b) -> a -> b
$ \Ptr (FFIResult (Ptr RawLister))
ffiResultPtr -> do
      Ptr RawOperator
-> CString -> Ptr (FFIResult (Ptr RawLister)) -> IO ()
c_blocking_list Ptr RawOperator
opptr CString
cPath Ptr (FFIResult (Ptr RawLister))
ffiResultPtr
      FFIResult (Ptr RawLister)
ffiResult <- forall a. Storable a => Ptr a -> IO a
peek Ptr (FFIResult (Ptr RawLister))
ffiResultPtr
      if forall a. FFIResult a -> CUInt
ffiCode FFIResult (Ptr RawLister)
ffiResult forall a. Eq a => a -> a -> Bool
== CUInt
0
        then do
          Ptr RawLister
ffilister <- forall a. Storable a => Ptr a -> IO a
peek forall a b. (a -> b) -> a -> b
$ forall a. FFIResult a -> Ptr a
dataPtr FFIResult (Ptr RawLister)
ffiResult
          Lister
lister <- ForeignPtr RawLister -> Lister
Lister forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> forall a. FinalizerPtr a -> Ptr a -> IO (ForeignPtr a)
newForeignPtr FunPtr (Ptr RawLister -> IO ())
c_free_lister Ptr RawLister
ffilister
          forall (m :: * -> *) a. Monad m => a -> m a
return forall a b. (a -> b) -> a -> b
$ forall a b. b -> Either a b
Right Lister
lister
        else do
          let code :: ErrorCode
code = Int -> ErrorCode
parseErrorCode forall a b. (a -> b) -> a -> b
$ forall a b. (Integral a, Num b) => a -> b
fromIntegral forall a b. (a -> b) -> a -> b
$ forall a. FFIResult a -> CUInt
ffiCode FFIResult (Ptr RawLister)
ffiResult
          String
errMsg <- CString -> IO String
peekCString (forall a. FFIResult a -> CString
errorMessage FFIResult (Ptr RawLister)
ffiResult)
          forall (m :: * -> *) a. Monad m => a -> m a
return forall a b. (a -> b) -> a -> b
$ forall a b. a -> Either a b
Left forall a b. (a -> b) -> a -> b
$ ErrorCode -> String -> OpenDALError
OpenDALError ErrorCode
code String
errMsg

-- | List dir in flat way.
-- Also, this function can be used to list a prefix.
-- An error will be returned if given path doesn’t end with /.
scanOpRaw :: Operator -> String -> IO (Either OpenDALError Lister)
scanOpRaw :: Operator -> String -> IO (Either OpenDALError Lister)
scanOpRaw (Operator ForeignPtr RawOperator
op) String
path = forall a b. ForeignPtr a -> (Ptr a -> IO b) -> IO b
withForeignPtr ForeignPtr RawOperator
op forall a b. (a -> b) -> a -> b
$ \Ptr RawOperator
opptr ->
  forall a. String -> (CString -> IO a) -> IO a
withCString String
path forall a b. (a -> b) -> a -> b
$ \CString
cPath ->
    forall a b. Storable a => (Ptr a -> IO b) -> IO b
alloca forall a b. (a -> b) -> a -> b
$ \Ptr (FFIResult (Ptr RawLister))
ffiResultPtr -> do
      Ptr RawOperator
-> CString -> Ptr (FFIResult (Ptr RawLister)) -> IO ()
c_blocking_scan Ptr RawOperator
opptr CString
cPath Ptr (FFIResult (Ptr RawLister))
ffiResultPtr
      FFIResult (Ptr RawLister)
ffiResult <- forall a. Storable a => Ptr a -> IO a
peek Ptr (FFIResult (Ptr RawLister))
ffiResultPtr
      if forall a. FFIResult a -> CUInt
ffiCode FFIResult (Ptr RawLister)
ffiResult forall a. Eq a => a -> a -> Bool
== CUInt
0
        then do
          Ptr RawLister
ffilister <- forall a. Storable a => Ptr a -> IO a
peek forall a b. (a -> b) -> a -> b
$ forall a. FFIResult a -> Ptr a
dataPtr FFIResult (Ptr RawLister)
ffiResult
          Lister
lister <- ForeignPtr RawLister -> Lister
Lister forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> forall a. FinalizerPtr a -> Ptr a -> IO (ForeignPtr a)
newForeignPtr FunPtr (Ptr RawLister -> IO ())
c_free_lister Ptr RawLister
ffilister
          forall (m :: * -> *) a. Monad m => a -> m a
return forall a b. (a -> b) -> a -> b
$ forall a b. b -> Either a b
Right Lister
lister
        else do
          let code :: ErrorCode
code = Int -> ErrorCode
parseErrorCode forall a b. (a -> b) -> a -> b
$ forall a b. (Integral a, Num b) => a -> b
fromIntegral forall a b. (a -> b) -> a -> b
$ forall a. FFIResult a -> CUInt
ffiCode FFIResult (Ptr RawLister)
ffiResult
          String
errMsg <- CString -> IO String
peekCString (forall a. FFIResult a -> CString
errorMessage FFIResult (Ptr RawLister)
ffiResult)
          forall (m :: * -> *) a. Monad m => a -> m a
return forall a b. (a -> b) -> a -> b
$ forall a b. a -> Either a b
Left forall a b. (a -> b) -> a -> b
$ ErrorCode -> String -> OpenDALError
OpenDALError ErrorCode
code String
errMsg

-- | Get next entry path from `Lister`.
nextLister :: Lister -> IO (Either OpenDALError (Maybe String))
nextLister :: Lister -> IO (Either OpenDALError (Maybe String))
nextLister (Lister ForeignPtr RawLister
lister) = forall a b. ForeignPtr a -> (Ptr a -> IO b) -> IO b
withForeignPtr ForeignPtr RawLister
lister forall a b. (a -> b) -> a -> b
$ \Ptr RawLister
listerptr ->
  forall a b. Storable a => (Ptr a -> IO b) -> IO b
alloca forall a b. (a -> b) -> a -> b
$ \Ptr (FFIResult CString)
ffiResultPtr -> do
    Ptr RawLister -> Ptr (FFIResult CString) -> IO ()
c_lister_next Ptr RawLister
listerptr Ptr (FFIResult CString)
ffiResultPtr
    FFIResult CString
ffiResult <- forall a. Storable a => Ptr a -> IO a
peek Ptr (FFIResult CString)
ffiResultPtr
    if forall a. FFIResult a -> CUInt
ffiCode FFIResult CString
ffiResult forall a. Eq a => a -> a -> Bool
== CUInt
0
      then do
        CString
val <- forall a. Storable a => Ptr a -> IO a
peek forall a b. (a -> b) -> a -> b
$ forall a. FFIResult a -> Ptr a
dataPtr FFIResult CString
ffiResult
        forall a b. b -> Either a b
Right forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> CString -> IO (Maybe String)
parseCString CString
val
      else do
        let code :: ErrorCode
code = Int -> ErrorCode
parseErrorCode forall a b. (a -> b) -> a -> b
$ forall a b. (Integral a, Num b) => a -> b
fromIntegral forall a b. (a -> b) -> a -> b
$ forall a. FFIResult a -> CUInt
ffiCode FFIResult CString
ffiResult
        String
errMsg <- CString -> IO String
peekCString (forall a. FFIResult a -> CString
errorMessage FFIResult CString
ffiResult)
        forall (m :: * -> *) a. Monad m => a -> m a
return forall a b. (a -> b) -> a -> b
$ forall a b. a -> Either a b
Left forall a b. (a -> b) -> a -> b
$ ErrorCode -> String -> OpenDALError
OpenDALError ErrorCode
code String
errMsg