packages feed

extism-pdk-0.2.0.0: src/Extism/PDK.hs

{-# LANGUAGE Rank2Types #-}

-- |
-- Extism plugin development kit, used with the [wasm32-wasi-ghc](https://gitlab.haskell.org/ghc/ghc-wasm-meta) backend to make Extism plugins
module Extism.PDK
  ( module Extism.PDK,
    ToBytes (..),
    FromBytes (..),
    JSONValue (..),
    MsgPackValue (..),
  )
where

import Data.ByteString as B
import Extism.PDK.Bindings
import Extism.PDK.Memory
import qualified Extism.PDK.MsgPack (MsgPack, decode, encode)
import Extism.PDK.Util
import Text.JSON (JSON, decode, encode, resultToEither)

-- | Get plugin input, returning an error message if the encoding is invalid
tryInput :: (FromBytes a) => IO (Either String a)
tryInput = fromBytes <$> inputByteString

-- | Get plugin input
input :: forall a. (FromBytes a) => IO a
input = do
  i <- inputByteString
  let x = fromBytes i
  case x of
    Left e -> error e
    Right y -> return y

-- | Get plugin input as a String
inputString :: IO String
inputString = do
  len <- extismInputLength
  fromByteString <$> readInputBytes len

-- | Get plugin input as a ByteString
inputByteString :: IO ByteString
inputByteString = do
  len <- extismInputLength
  readInputBytes len

-- | Get input as 'JSON', this is similar to calling `input (JsonValue ...)`
inputJSON :: (JSON a) => IO (Either String a)
inputJSON = do
  s <- tryInput :: IO (Either String String)
  case s of
    Left e -> return (Left e)
    Right x ->
      case resultToEither $ decode x of
        Left e -> return (Left e)
        Right y -> return (Right y)

-- | Set plugin output
output :: (ToBytes a) => a -> IO ()
output x = do
  Memory offs len <- alloc x
  extismSetOutput offs len

-- | Set plugin output to a JSON encoded version of the provided value
outputJSON :: (JSON a) => a -> IO ()
outputJSON x =
  output (encode x)

-- | Get a variable from the Extism runtime
getVar :: (FromBytes a) => String -> IO (Maybe a)
getVar key = do
  k <- allocString key
  v <- extismGetVar (memoryOffset k)
  free k
  if v == 0
    then return Nothing
    else do
      mem <- findMemory v
      bs <- load mem
      free k
      case bs of
        Left _ -> return Nothing
        Right x -> return (Just x)

-- | Set a variable
setVar :: (ToBytes a) => String -> Maybe a -> IO ()
setVar key Nothing = do
  k <- allocString key
  extismSetVar (memoryOffset k) 0
  free k
setVar key (Just v) = do
  k <- allocString key
  x <- alloc v
  extismSetVar (memoryOffset k) (memoryOffset x)
  free k
  free x

-- | Get a configuration value
getConfig :: String -> IO (Maybe String)
getConfig key = do
  k <- allocString key
  v <- extismGetConfig (memoryOffset k)
  free k
  if v == 0
    then return Nothing
    else do
      mem <- findMemory v
      s <- loadString mem
      free mem
      return $ Just s

-- | Set the current error message
setError :: String -> IO ()
setError msg = do
  s <- allocString msg
  extismSetError $ memoryOffset s

-- | Log level
data LogLevel = Info | Debug | Warn | Error

-- | Log to configured log file
log :: LogLevel -> String -> IO ()
log Info msg = do
  s <- allocString msg
  extismLogInfo (memoryOffset s)
  free s
log Debug msg = do
  s <- allocString msg
  extismLogDebug (memoryOffset s)
  free s
log Warn msg = do
  s <- allocString msg
  extismLogWarn (memoryOffset s)
  free s
log Error msg = do
  s <- allocString msg
  extismLogError (memoryOffset s)
  free s