extism-pdk 0.2.0.0 → 1.0.0.0
raw patch · 11 files changed
+185/−56 lines, 11 filesdep ~extism-manifestPVP ok
version bump matches the API change (PVP)
Dependency ranges changed: extism-manifest
API changes (from Hackage documentation)
- Extism.PDK: Debug :: LogLevel
- Extism.PDK: Error :: LogLevel
- Extism.PDK: Info :: LogLevel
- Extism.PDK: JSONValue :: a -> JSONValue a
- Extism.PDK: MsgPackValue :: a -> MsgPackValue a
- Extism.PDK: Warn :: LogLevel
- Extism.PDK: newtype JSONValue a
- Extism.PDK: newtype MsgPackValue a
- Extism.PDK.HTTP: type Request = HTTPRequest
- Extism.PDK.Memory: JSONValue :: a -> JSONValue a
- Extism.PDK.Memory: MsgPackValue :: a -> MsgPackValue a
- Extism.PDK.Memory: instance Extism.PDK.MsgPack.MsgPack a => Extism.PDK.Memory.FromBytes (Extism.PDK.Memory.MsgPackValue a)
- Extism.PDK.Memory: instance Extism.PDK.MsgPack.MsgPack a => Extism.PDK.Memory.ToBytes (Extism.PDK.Memory.MsgPackValue a)
- Extism.PDK.Memory: instance Text.JSON.JSON a => Extism.PDK.Memory.FromBytes (Extism.PDK.Memory.JSONValue a)
- Extism.PDK.Memory: instance Text.JSON.JSON a => Extism.PDK.Memory.ToBytes (Extism.PDK.Memory.JSONValue a)
- Extism.PDK.Memory: newtype JSONValue a
- Extism.PDK.Memory: newtype MsgPackValue a
+ Extism.PDK: JSON :: a -> JSON a
+ Extism.PDK: LogDebug :: LogLevel
+ Extism.PDK: LogError :: LogLevel
+ Extism.PDK: LogInfo :: LogLevel
+ Extism.PDK: LogWarn :: LogLevel
+ Extism.PDK: MsgPack :: a -> MsgPack a
+ Extism.PDK: logDebug :: String -> IO ()
+ Extism.PDK: logError :: String -> IO ()
+ Extism.PDK: logInfo :: String -> IO ()
+ Extism.PDK: logWarn :: String -> IO ()
+ Extism.PDK: newtype JSON a
+ Extism.PDK: newtype MsgPack a
+ Extism.PDK.Bindings: extismLengthUnsafe :: MemoryOffset -> IO MemoryLength
+ Extism.PDK.HTTP: Request :: String -> [(String, String)] -> String -> Request
+ Extism.PDK.HTTP: [headers] :: Request -> [(String, String)]
+ Extism.PDK.HTTP: [method] :: Request -> String
+ Extism.PDK.HTTP: [url] :: Request -> String
+ Extism.PDK.HTTP: data Request
+ Extism.PDK.HTTP: instance Data.Data.Data Extism.PDK.HTTP.Request
+ Extism.PDK.Memory: JSON :: a -> JSON a
+ Extism.PDK.Memory: MsgPack :: a -> MsgPack a
+ Extism.PDK.Memory: instance Data.Data.Data a => Extism.PDK.Memory.FromBytes (Extism.PDK.Memory.JSON a)
+ Extism.PDK.Memory: instance Data.Data.Data a => Extism.PDK.Memory.ToBytes (Extism.PDK.Memory.JSON a)
+ Extism.PDK.Memory: instance Extism.PDK.MsgPack.MsgPack a => Extism.PDK.Memory.FromBytes (Extism.PDK.Memory.MsgPack a)
+ Extism.PDK.Memory: instance Extism.PDK.MsgPack.MsgPack a => Extism.PDK.Memory.ToBytes (Extism.PDK.Memory.MsgPack a)
+ Extism.PDK.Memory: newtype JSON a
+ Extism.PDK.Memory: newtype MsgPack a
- Extism.PDK: inputJSON :: JSON a => IO (Either String a)
+ Extism.PDK: inputJSON :: Data a => IO a
- Extism.PDK: outputJSON :: JSON a => a -> IO ()
+ Extism.PDK: outputJSON :: Data a => a -> IO ()
- Extism.PDK.HTTP: responseJSON :: JSON a => Response -> IO (Either String a)
+ Extism.PDK.HTTP: responseJSON :: Data a => Response -> IO (Either String a)
Files
- CHANGELOG.md +4/−0
- examples/CountVowels.hs +9/−1
- examples/HTTPGet.hs +1/−1
- examples/Hello.hs +3/−1
- extism-pdk.cabal +3/−2
- src/Extism/PDK.hs +29/−18
- src/Extism/PDK/Bindings.hs +2/−0
- src/Extism/PDK/HTTP.hs +37/−17
- src/Extism/PDK/JSON.hs +3/−1
- src/Extism/PDK/Memory.hs +19/−15
- src/extism-pdk.c +75/−0
CHANGELOG.md view
@@ -1,5 +1,9 @@ # Revision history for extism-pdk +## 1.0.0.0++* Extism 1.0 compatible release+ ## 0.2.0.0 * API redesign, add automatic Haskell encoding using `ToMemory` and `FromMemory` classes
examples/CountVowels.hs view
@@ -1,8 +1,16 @@+{-# LANGUAGE DeriveDataTypeable #-}+ module CountVowels where import Extism.PDK import Extism.PDK.JSON +data Output = Output+ { count :: Int+ }+ deriving+ (Data, Typeable)+ isVowel c = c == 'a' || c == 'A'@@ -21,6 +29,6 @@ -- Calculate the number of vowels let count = length (filter isVowel s) -- Return a JSON object {"count": count} back to the host- output $ JSONValue $ object ["count" .= count]+ output $ JSON $ Output count foreign export ccall "count_vowels" countVowels :: IO ()
examples/HTTPGet.hs view
@@ -8,7 +8,7 @@ getInput = do req <- tryInput case req of- Right (JSONValue x) -> return x+ Right (JSON x) -> return x Left e -> do putStrLn e url <- inputString
examples/Hello.hs view
@@ -1,8 +1,10 @@+{-# LANGUAGE DeriveDataTypeable #-}+ module Hello where import Data.Maybe import Extism.PDK-import Foreign.C.Types+import Extism.PDK.JSON defaultGreeting = "Hello"
extism-pdk.cabal view
@@ -1,6 +1,6 @@ cabal-version: 3.0 name: extism-pdk-version: 0.2.0.0+version: 1.0.0.0 -- A short (one-line) description of the package. synopsis: Extism Plugin Development Kit@@ -39,13 +39,14 @@ bytestring >= 0.11.4 && <= 0.12, cereal >= 0.5.8 && < 0.6, containers >= 0.6.7 && < 0.7,- extism-manifest >= 0.3.0 && <= 1.0.0,+ extism-manifest >= 1.0.0 && < 2.0.0, json >= 0.11 && < 0.12, messagepack >= 0.5.5 && < 0.6, binary >= 0.8.9 && < 0.9.0 hs-source-dirs: src default-language: Haskell2010+ c-sources: src/extism-pdk.c executable hello scope: private
src/Extism/PDK.hs view
@@ -6,8 +6,8 @@ ( module Extism.PDK, ToBytes (..), FromBytes (..),- JSONValue (..),- MsgPackValue (..),+ JSON (..),+ MsgPack (..), ) where @@ -16,7 +16,8 @@ import Extism.PDK.Memory import qualified Extism.PDK.MsgPack (MsgPack, decode, encode) import Extism.PDK.Util-import Text.JSON (JSON, decode, encode, resultToEither)+import qualified Text.JSON (decode, encode, resultToEither)+import qualified Text.JSON.Generic -- | Get plugin input, returning an error message if the encoding is invalid tryInput :: (FromBytes a) => IO (Either String a)@@ -44,15 +45,9 @@ readInputBytes len -- | Get input as 'JSON', this is similar to calling `input (JsonValue ...)`-inputJSON :: (JSON a) => IO (Either String a)+inputJSON :: (Text.JSON.Generic.Data a) => IO 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)+ Text.JSON.Generic.decodeJSON <$> input -- | Set plugin output output :: (ToBytes a) => a -> IO ()@@ -61,9 +56,9 @@ extismSetOutput offs len -- | Set plugin output to a JSON encoded version of the provided value-outputJSON :: (JSON a) => a -> IO ()+outputJSON :: (Text.JSON.Generic.Data a) => a -> IO () outputJSON x =- output (encode x)+ output (Text.JSON.Generic.encodeJSON x) -- | Get a variable from the Extism runtime getVar :: (FromBytes a) => String -> IO (Maybe a)@@ -115,23 +110,39 @@ extismSetError $ memoryOffset s -- | Log level-data LogLevel = Info | Debug | Warn | Error+data LogLevel = LogInfo | LogDebug | LogWarn | LogError -- | Log to configured log file log :: LogLevel -> String -> IO ()-log Info msg = do+log LogInfo msg = do s <- allocString msg extismLogInfo (memoryOffset s) free s-log Debug msg = do+log LogDebug msg = do s <- allocString msg extismLogDebug (memoryOffset s) free s-log Warn msg = do+log LogWarn msg = do s <- allocString msg extismLogWarn (memoryOffset s) free s-log Error msg = do+log LogError msg = do s <- allocString msg extismLogError (memoryOffset s) free s++-- Log with "error" level+logError :: String -> IO ()+logError = Extism.PDK.log LogError++-- Log with "info" level+logInfo :: String -> IO ()+logInfo = Extism.PDK.log LogInfo++-- Log with "debug" level+logDebug :: String -> IO ()+logDebug = Extism.PDK.log LogDebug++-- Log with "warn" level+logWarn :: String -> IO ()+logWarn = Extism.PDK.log LogWarn
src/Extism/PDK/Bindings.hs view
@@ -49,6 +49,8 @@ foreign import ccall "extism_length" extismLength :: MemoryOffset -> IO MemoryLength +foreign import ccall "extism_length_unsafe" extismLengthUnsafe :: MemoryOffset -> IO MemoryLength+ foreign import ccall "extism_free" extismFree :: MemoryOffset -> IO () foreign import ccall "extism_input_length" extismInputLength :: IO InputLength
src/Extism/PDK/HTTP.hs view
@@ -1,17 +1,26 @@+{-# LANGUAGE DeriveDataTypeable #-}+ -- | -- Contains bindings to the Extism PDK HTTP interface module Extism.PDK.HTTP where import Data.ByteString as B import Data.Word-import Extism.JSON (JSON, Nullable (..), Result (..), decode)-import Extism.Manifest (HTTPRequest (..), headers, method, toString, url)+import Extism.JSON (Nullable (..))+import qualified Extism.Manifest (HTTPRequest (..)) import Extism.PDK import Extism.PDK.Bindings import Extism.PDK.Memory+import Text.JSON (Result(..), decode, encode, makeObj)+import qualified Text.JSON.Generic -- | HTTP Request-type Request = HTTPRequest+data Request = Request+ { url :: String,+ headers :: [(String, String)],+ method :: String+ }+ deriving (Text.JSON.Generic.Typeable, Text.JSON.Generic.Data) -- | HTTP Response data Response = Response@@ -22,21 +31,17 @@ -- | Creates a new 'Request' newRequest :: String -> Request newRequest url =- HTTPRequest- { url = url,- headers = Null,- method = Null- }+ Request url [] "GET" -- | Update a 'Request' with the provided HTTP request method (GET, POST, PUT, DELETE, ...) withMethod :: String -> Request -> Request withMethod meth req =- req {method = NotNull meth}+ req {method = meth} -- | Update a 'Request' with the provided HTTP request headers withHeaders :: [(String, String)] -> Request -> Request withHeaders h req =- req {headers = NotNull h}+ req {headers = h} -- | Access the Memory block associated with a 'Response' responseMemory :: Response -> Memory@@ -55,12 +60,15 @@ responseString (Response _ mem) = loadString mem -- | Get the 'Response' body as JSON-responseJSON :: (JSON a) => Response -> IO (Either String a)+responseJSON :: (Text.JSON.Generic.Data a) => Response -> IO (Either String a) responseJSON (Response _ mem) = do json <- decode <$> loadString mem case json of- Ok json -> return $ Right json- Extism.JSON.Error msg -> return (Left msg)+ Ok json ->+ case Text.JSON.Generic.fromJSON json of+ Ok x -> return $ Right x+ Error msg -> return (Left msg)+ Error msg -> return (Left msg) -- | Get the 'Response' body and decode it response :: (FromBytes a) => Response -> IO (Either String a)@@ -70,7 +78,13 @@ sendRequestWithBody :: (ToBytes a) => Request -> a -> IO Response sendRequestWithBody req b = do body <- alloc b- let json = Extism.Manifest.toString req+ let json =+ encode+ Extism.Manifest.HTTPRequest+ { Extism.Manifest.url = url req,+ Extism.Manifest.headers = NotNull $ headers req,+ Extism.Manifest.method = NotNull $ method req+ } j <- allocString json res <- extismHTTPRequest (memoryOffset j) (memoryOffset body) free j@@ -85,7 +99,13 @@ -- | Send HTTP request with an optional request body sendRequest :: (ToBytes a) => Request -> Maybe a -> IO Response sendRequest req b =- let json = Extism.Manifest.toString req+ let json =+ encode+ Extism.Manifest.HTTPRequest+ { Extism.Manifest.url = url req,+ Extism.Manifest.headers = NotNull $ headers req,+ Extism.Manifest.method = NotNull $ method req+ } in let bodyMem = case b of Nothing -> return $ Memory 0 0 Just b -> alloc b@@ -99,5 +119,5 @@ if res == 0 then return (Response (fromIntegral code) (Memory 0 0)) else do- mem <- findMemory res- return (Response (fromIntegral code) mem)+ len <- extismLengthUnsafe res+ return (Response (fromIntegral code) (Memory res len))
src/Extism/PDK/JSON.hs view
@@ -1,7 +1,9 @@ module Extism.PDK.JSON ( module Extism.PDK.JSON, module Extism.JSON,+ module Text.JSON.Generic, ) where -import Extism.JSON+import qualified Extism.JSON+import Text.JSON.Generic
src/Extism/PDK/Memory.hs view
@@ -8,8 +8,8 @@ MemoryLength, FromBytes (..), ToBytes (..),- JSONValue (..),- MsgPackValue (..),+ JSON (..),+ MsgPack (..), load, loadString, loadByteString,@@ -34,7 +34,8 @@ import Extism.PDK.Bindings import qualified Extism.PDK.MsgPack (MsgPack, decode, encode) import Extism.PDK.Util-import Text.JSON (JSON, decode, encode, resultToEither)+import qualified Text.JSON (JSON, Result (..), decode, encode)+import qualified Text.JSON.Generic -- | Represents a block of memory by offset and length data Memory = Memory MemoryOffset MemoryLength@@ -135,10 +136,10 @@ toBytes :: a -> B.ByteString -- | A wrapper type for JSON encoded values-newtype JSONValue a = JSONValue a+newtype JSON a = JSON a -- | A wrapper type for MsgPack encoded values-newtype MsgPackValue a = MsgPackValue a+newtype MsgPack a = MsgPack a instance FromBytes B.ByteString where fromBytes = Right@@ -156,20 +157,23 @@ instance ToBytes String where toBytes = toByteString -instance (JSON a) => FromBytes (JSONValue a) where+instance (Text.JSON.Generic.Data a) => FromBytes (JSON a) where fromBytes mem = let a = fromBytes mem in case a of Left e -> Left e Right x ->- case resultToEither $ decode x of- Left e -> Left e- Right y -> Right (JSONValue y)+ case Text.JSON.decode x of+ Text.JSON.Error e -> Left e+ Text.JSON.Ok y ->+ case Text.JSON.Generic.fromJSON y of+ Text.JSON.Error e -> Left e+ Text.JSON.Ok z -> Right (JSON z) -instance (JSON a) => ToBytes (JSONValue a) where- toBytes (JSONValue x) = toBytes (encode x)+instance (Text.JSON.Generic.Data a) => ToBytes (JSON a) where+ toBytes (JSON x) = toBytes (Text.JSON.Generic.encodeJSON x) -instance (Extism.PDK.MsgPack.MsgPack a) => FromBytes (MsgPackValue a) where+instance (Extism.PDK.MsgPack.MsgPack a) => FromBytes (MsgPack a) where fromBytes mem = let a = fromBytes mem in case a of@@ -177,10 +181,10 @@ Right x -> case Extism.PDK.MsgPack.decode x of Left e -> Left e- Right y -> Right (MsgPackValue y)+ Right y -> Right (MsgPack y) -instance (Extism.PDK.MsgPack.MsgPack a) => ToBytes (MsgPackValue a) where- toBytes (MsgPackValue x) = toBytes $ Extism.PDK.MsgPack.encode x+instance (Extism.PDK.MsgPack.MsgPack a) => ToBytes (MsgPack a) where+ toBytes (MsgPack x) = toBytes $ Extism.PDK.MsgPack.encode x instance ToBytes Int32 where toBytes i = toBytes $ B.toStrict (runPut (putInt32le i))
+ src/extism-pdk.c view
@@ -0,0 +1,75 @@+#include <stdint.h>++#define IMPORT(a, b) __attribute__((import_module(a), import_name(b)))++typedef uint64_t ExtismPointer;++#define DEFINE(name, t, ...) \+ IMPORT("extism:host/env", #name) extern t _##name(__VA_ARGS__);++DEFINE(input_length, uint64_t)+uint64_t extism_input_length() { return _input_length(); }++DEFINE(length, uint64_t, ExtismPointer)+uint64_t extism_length(ExtismPointer p) { return _length(p); }++DEFINE(length_unsafe, uint64_t, ExtismPointer)+uint64_t extism_length_unsafe(ExtismPointer p) { return _length_unsafe(p); }++DEFINE(alloc, ExtismPointer, uint64_t)+uint64_t extism_alloc(uint64_t n) { return _alloc(n); }++DEFINE(free, void, ExtismPointer)+void extism_free(uint64_t n) { return _free(n); }++DEFINE(input_load_u8, uint8_t, ExtismPointer)+uint8_t extism_input_load_u8(ExtismPointer p) { return _input_load_u8(p); }++DEFINE(input_load_u64, uint64_t, ExtismPointer)+uint64_t extism_input_load_u64(ExtismPointer p) { return _input_load_u64(p); }++DEFINE(output_set, void, ExtismPointer, uint64_t)+void extism_output_set(ExtismPointer p, uint64_t n) {+ return _output_set(p, n);+}++DEFINE(error_set, void, ExtismPointer)+void extism_error_set(ExtismPointer p) { _error_set(p); }++DEFINE(config_get, ExtismPointer, ExtismPointer)+ExtismPointer extism_config_get(ExtismPointer p) { return _config_get(p); }++DEFINE(var_get, ExtismPointer, ExtismPointer)+ExtismPointer extism_var_get(ExtismPointer p) { return _var_get(p); }++DEFINE(var_set, void, ExtismPointer, ExtismPointer)+void extism_var_set(ExtismPointer k, ExtismPointer v) { return _var_set(k, v); }++DEFINE(store_u8, void, ExtismPointer, uint8_t)+void extism_store_u8(ExtismPointer p, uint8_t x) { return _store_u8(p, x); }++DEFINE(load_u8, uint8_t, ExtismPointer)+uint8_t extism_load_u8(ExtismPointer p) { return _load_u8(p); }++DEFINE(store_u64, void, ExtismPointer, uint64_t)+void extism_store_u64(ExtismPointer p, uint64_t x) { return _store_u64(p, x); }++DEFINE(load_u64, uint64_t, ExtismPointer)+uint64_t extism_load_u64(ExtismPointer p) { return _load_u64(p); }++DEFINE(http_request, ExtismPointer, ExtismPointer, ExtismPointer)+ExtismPointer extism_http_request(ExtismPointer req, ExtismPointer body) {+ return _http_request(req, body);+}++DEFINE(http_status_code, int32_t)+int32_t extism_http_status_code() { return _http_status_code(); }++DEFINE(log_info, void, ExtismPointer)+void extism_log_info(ExtismPointer p) { return _log_info(p); }+DEFINE(log_debug, void, ExtismPointer)+void extism_log_debug(ExtismPointer p) { return _log_debug(p); }+DEFINE(log_warn, void, ExtismPointer)+void extism_warn_info(ExtismPointer p) { return _log_warn(p); }+DEFINE(log_error, void, ExtismPointer)+void extism_log_error(ExtismPointer p) { return _log_error(p); }