amqp-utils 0.6.6.0 → 0.6.7.2
raw patch · 5 files changed
+142/−96 lines, 5 filesdep ~amqpdep ~bytestringdep ~containers
Dependency ranges changed: amqp, bytestring, containers, crypton-connection, crypton-x509-system, data-default-class, directory, filepath, filepath-bytestring, hinotify, magic, network, process, rawfilepath, text, time, tls, unix, utf8-string
Files
- ChangeLog.md +14/−0
- Network/AMQP/Utils/Options.hs +8/−0
- README.md +9/−5
- agitprop.hs +45/−25
- amqp-utils.cabal +66/−66
ChangeLog.md view
@@ -6,6 +6,20 @@ # Revision history for haskell-amqp-utils +## 0.6.7.2 -- 2025-07-29++* add cabal bounds+* add copy-to-hotfolder simple callback script+* update flake to nixos-25.05+* update stack.yaml to lts-24.2 (ghc-9.10.2)+* fix builds.sr.ht openbsd and alpine builds+* add Dockerfile for static linux binaries (thanks mdom)+* agitprop:+ * ignore dotfiles even without -S+ * only send regular files in hotfolder mode+ * add --watchcreate (-L) option to get hardlink events+ * ignore empty files with --watchcreate (-L)+ ## 0.6.6.0 -- 2024-12-06 * LineBuffering
Network/AMQP/Utils/Options.hs view
@@ -82,6 +82,7 @@ , initialScan :: Bool , streamoffset :: FieldTable , delaynack :: Int+ , watchCreate :: Bool } instance Default Args where@@ -138,6 +139,7 @@ False (FieldTable M.empty) 0+ False -- | all options allOptions :: [(String, OptDescr (Args -> Args))]@@ -475,6 +477,12 @@ (ReqArg (\s o -> o {delaynack = read s}) "SECONDS") ("delay negative acknowledgements (default: " ++ show (delaynack def) ++ ")"))+ , ( "a"+ , Option+ ['L']+ ["watchcreate"]+ (NoArg (\o -> o {watchCreate = not (watchCreate o)}))+ ("Toggle watching Create (ln) events in hotfolder mode (default: " ++ show (watchCreate def) ++ ")")) ] -- | Options for the executables
README.md view
@@ -11,7 +11,7 @@ - publisher (`agitprop`) - rpc client and worker (`plane` / `arbeite`) -## konsum - an AMQP consumer.+## konsum - AMQP consumer. **konsum** [*options*] @@ -78,7 +78,7 @@ Stop with ^C -## agitprop - an AMQP publisher+## agitprop - AMQP publisher **agitprop** [*options*] @@ -89,7 +89,8 @@ optionally only files which match one or several SUFFIXes. Optionally the file name is written into a message header named HEADERNAME. Optionally Content-Type and Content-Encoding headers are set via magic retrieved from file-contents.+contents. Filenames beginning with a dot (.) are ignored. With -L also files+created by hardlinking are recognized, empty files are ignored. Line-by-line mode sends one message per INPUTFILE line. @@ -132,6 +133,7 @@ -s INT --heartbeats=INT heartbeat interval (0=disable, default: set by server) -n NAME --name=NAME connection name, will be shown in RabbitMQ web interface -w SECONDS --connect_timeout=SECONDS timeout for establishing initial connection (default: 600)+ -L --watchcreate Toggle watching Create (ln) events in hotfolder mode (default: False) ### EXAMPLES @@ -147,7 +149,7 @@ agitprop -x amq.topic -F fileName -m -S .txt -S .zip -d -udone -r r1 -f dir1 -r r2 -f dir2 -## plane - an AMQP RPC client.+## plane - AMQP RPC client. **plane** [*options*] @@ -180,7 +182,7 @@ echo ls | plane -o amqp.example.com -T -k amqp.pem -c amqp.pem -y myexchange -Q rpctest -## arbeite - an AMQP RPC worker.+## arbeite - AMQP RPC worker. **arbeite** [*options*] @@ -296,6 +298,8 @@ - git://woffs.de/git/fd/haskell-amqp-utils.git - https://woffs.de/git/fd/haskell-amqp-utils.git - https://git.sr.ht/~woffs/haskell-amqp-utils+ - https://git.disroot.org/woffs/haskell-amqp-utils+ - [Radicle](https://radicle.xyz): `rad clone rad:zMhy3AsYnY2QHcfQuVGVW9N5RsRJ` - Repology: https://repology.org/project/haskell:amqp-utils/packages - Hackage: https://hackage.haskell.org/package/amqp-utils - Stackage: https://www.stackage.org/package/amqp-utils
agitprop.hs view
@@ -8,7 +8,7 @@ -- generic AMQP publisher import Control.Concurrent import qualified Control.Exception as X-import Control.Monad (forM_)+import Control.Monad (forM_, when) import qualified Data.ByteString.Char8 as BS import qualified Data.ByteString.Lazy.Char8 as BL import qualified Data.Map as M@@ -64,6 +64,7 @@ then do printparam "hotfolder mode" True printparam "initial scan" (initialScan args)+ printparam "watch create events" (watchCreate args) if isNothing (moveSentFileTo args) then printparam "remove sent file" (removeSentFile args) else printparam "move sent file to" (moveSentFileTo args)@@ -116,17 +117,23 @@ printparam "hotfolder" folder inotify <- initINotify wd <-- addWatch- inotify- [CloseWrite, MoveIn]- folder- (handleEvent (publishOneMsg exchange rkey) (suffix args) folder)+ addWatch+ inotify+ [CloseWrite, MoveIn, Create]+ folder+ (handleEvent (publishOneMsg exchange rkey) (suffix args) (watchCreate args) folder) hr "BEGIN watching" if (initialScan args)- then RD.listDirectory folder >>=- mapM_ (\fn -> handleFile (publishOneMsg exchange rkey) (suffix args) (folder </> fn))- else return ()- return (wd,folder)+ then RD.listDirectory folder+ >>= mapM_+ (\fn ->+ handleFile+ (publishOneMsg exchange rkey)+ (suffix args)+ folder+ fn)+ else return ()+ return (wd, folder) #endif -- | A handler for clean exit@@ -152,25 +159,38 @@ #if linux_HOST_OS -- | Hotfolder event handler handleEvent ::- (Maybe RawFilePath -> BL.ByteString -> IO ()) -> [BS.ByteString] -> RawFilePath -> Event -> IO ()+ (Maybe RawFilePath -> BL.ByteString -> IO ()) -> [BS.ByteString] -> Bool -> RawFilePath -> Event -> IO () -- just handle closewrite and movedin events-handleEvent func suffixes folder (Closed False (Just fileName) True) =- handleFile func suffixes (folder </> fileName)-handleEvent func suffixes folder (MovedIn False fileName _) =- handleFile func suffixes (folder </> fileName)-handleEvent _ _ _ _ = return ()+handleEvent func suffixes _ folder (Closed False (Just fileName) True) =+ handleFile func suffixes folder fileName+handleEvent func suffixes _ folder (MovedIn False fileName _) =+ handleFile func suffixes folder fileName+-- handle create events when requested (detects ln)+handleEvent func suffixes True folder (Created False fileName) =+ handleFile func suffixes folder fileName+handleEvent _ _ _ _ _ = return () -- | Hotfolder file handler handleFile ::- (Maybe RawFilePath -> BL.ByteString -> IO ()) -> [BS.ByteString] -> RawFilePath -> IO ()-handleFile func suffixes@(_:_) fileName =- if (any (flip BS.isSuffixOf fileName) suffixes) && not ("." `BS.isPrefixOf` fileName)- then handleFile func [] fileName- else return ()-handleFile func [] fileName =- X.catch- (readFileRawLazy fileName >>= func (Just fileName))- (\e -> printparam "exception while processing" fileName >> printparam "exception in handleFile" (e :: X.IOException))+ (Maybe RawFilePath -> BL.ByteString -> IO ())+ -> [BS.ByteString]+ -> RawFilePath+ -> RawFilePath+ -> IO ()+handleFile func suffixes@(_:_) folder fileName =+ when+ (any (flip BS.isSuffixOf fileName) suffixes)+ (handleFile func [] folder fileName)+handleFile func [] folder fileName = do+ fStatus <- F.getFileStatus path+ when (not ("." `BS.isPrefixOf` fileName) && F.isRegularFile fStatus && F.fileSize fStatus > 0)+ $ X.catch+ (readFileRawLazy path >>= func (Just path))+ (\e ->+ printparam "exception while processing" fileName+ >> printparam "exception in handleFile" (e :: X.IOException))+ where+ path = folder </> fileName #endif -- | Publish one message with our settings
amqp-utils.cabal view
@@ -4,7 +4,7 @@ name: amqp-utils -version: 0.6.6.0+version: 0.6.7.2 synopsis: AMQP toolset for the command line @@ -37,22 +37,22 @@ executable konsum main-is: konsum.hs- build-depends: base >= 4.6 && <5,- containers,- text,- crypton-connection,- data-default-class,- time,- process,- directory,- bytestring,- utf8-string,- filepath-bytestring,- crypton-x509-system,- network > 2.6,- tls >= 1.7.0,- amqp >= 0.22.2,- unix >= 2.8+ build-depends: base >= 4.6 && < 5,+ containers >= 0.6 && < 0.8,+ text >= 2.0 && < 2.2,+ crypton-connection >= 0.3 && < 0.5,+ data-default-class >= 0.1 && < 0.3,+ time >= 1.12 && < 1.13,+ process >= 1.6 && < 1.7,+ directory >= 1.3 && < 1.4,+ bytestring >= 0.11 && < 0.13,+ utf8-string >= 1.0 && < 1.1,+ filepath-bytestring >= 1.4 && < 1.6,+ crypton-x509-system >= 1.6 && < 1.7,+ network > 2.6 && < 3.3,+ tls >= 1.7.0 && < 2.2,+ amqp >= 0.22.2 && < 0.25,+ unix >= 2.8 && < 2.9 ghc-options: -threaded -Wall @@ -66,26 +66,26 @@ executable agitprop main-is: agitprop.hs build-depends: base >= 4.6 && <5,- containers,- text,- crypton-connection,- data-default-class,- time,- process,- directory,- filepath,- bytestring,- utf8-string,- rawfilepath,- filepath-bytestring,- crypton-x509-system,- network > 2.6,- tls >= 1.7.0,- amqp >= 0.22.2,- unix >= 2.8,- magic+ containers >= 0.6 && < 0.8,+ text >= 2.0 && < 2.2,+ crypton-connection >= 0.3 && < 0.5,+ data-default-class >= 0.1 && < 0.3,+ time >= 1.12 && < 1.13,+ process >= 1.6 && < 1.7,+ directory >= 1.3 && < 1.4,+ bytestring >= 0.11 && < 0.13,+ utf8-string >= 1.0 && < 1.1,+ filepath-bytestring >= 1.4 && < 1.6,+ crypton-x509-system >= 1.6 && < 1.7,+ network > 2.6 && < 3.3,+ tls >= 1.7.0 && < 2.2,+ amqp >= 0.22.2 && < 0.25,+ unix >= 2.8 && < 2.9,+ filepath >= 1.4 && < 1.6,+ rawfilepath >= 1.1.1 && < 1.2,+ magic >= 1.1 && < 1.2 if os(linux)- build-depends: hinotify >= 0.3.10+ build-depends: hinotify >= 0.3.10 && < 0.5 ghc-options: -threaded -Wall @@ -99,21 +99,21 @@ executable plane main-is: plane.hs build-depends: base >=4.6 && <5,- containers,- text,- crypton-connection,- data-default-class,- time,- process,- directory,- bytestring,- utf8-string,- filepath-bytestring,- crypton-x509-system,- network > 2.6,- tls >= 1.7.0,- amqp >=0.22.2,- unix >= 2.8+ containers >= 0.6 && < 0.8,+ text >= 2.0 && < 2.2,+ crypton-connection >= 0.3 && < 0.5,+ data-default-class >= 0.1 && < 0.3,+ time >= 1.12 && < 1.13,+ process >= 1.6 && < 1.7,+ directory >= 1.3 && < 1.4,+ bytestring >= 0.11 && < 0.13,+ utf8-string >= 1.0 && < 1.1,+ filepath-bytestring >= 1.4 && < 1.6,+ crypton-x509-system >= 1.6 && < 1.7,+ network > 2.6 && < 3.3,+ tls >= 1.7.0 && < 2.2,+ amqp >= 0.22.2 && < 0.25,+ unix >= 2.8 && < 2.9 ghc-options: -threaded -Wall @@ -127,21 +127,21 @@ executable arbeite main-is: arbeite.hs build-depends: base >= 4.6 && <5,- containers,- text,- crypton-connection,- data-default-class,- time,- process,- directory,- bytestring,- utf8-string,- filepath-bytestring,- crypton-x509-system,- network > 2.6,- tls >= 1.7.0,- amqp >= 0.22.2,- unix >= 2.8+ containers >= 0.6 && < 0.8,+ text >= 2.0 && < 2.2,+ crypton-connection >= 0.3 && < 0.5,+ data-default-class >= 0.1 && < 0.3,+ time >= 1.12 && < 1.13,+ process >= 1.6 && < 1.7,+ directory >= 1.3 && < 1.4,+ bytestring >= 0.11 && < 0.13,+ utf8-string >= 1.0 && < 1.1,+ filepath-bytestring >= 1.4 && < 1.6,+ crypton-x509-system >= 1.6 && < 1.7,+ network > 2.6 && < 3.3,+ tls >= 1.7.0 && < 2.2,+ amqp >= 0.22.2 && < 0.25,+ unix >= 2.8 && < 2.9 ghc-options: -threaded -Wall