1 {-# LANGUAGE OverloadedStrings #-}
3 import Control.Concurrent (threadDelay)
4 import qualified Control.Exception as X
5 import Control.Monad (forever)
6 import qualified Data.ByteString.Lazy.Char8 as BL
7 import Data.List (isSuffixOf)
9 import qualified Data.Text as T
11 import Data.Time.Clock.POSIX
12 import Data.Version (showVersion)
13 import Data.Word (Word64)
16 import Network.AMQP.Types
17 import Network.AMQP.Utils.Connection
18 import Network.AMQP.Utils.Helpers
19 import Network.AMQP.Utils.Options
20 import Paths_amqp_utils (version)
21 import System.Environment
23 import qualified System.Posix.Files as F
28 args <- getArgs >>= parseargs "agitprop"
29 printparam' "client version" $ "amqp-utils " ++ (showVersion version)
30 printparam' "routing key" $ rKey args
31 isDir <- F.getFileStatus (inputFile args) >>= return . F.isDirectory
33 then printparam' "hotfolder" $ inputFile args
34 else printparam' "input file" $
37 then " (line-by-line)"
39 (conn, chan) <- connect args
40 printparam' "confirm mode" $ show $ confirm args
43 confirmSelect chan False
44 addConfirmationListener chan confirmCallback
46 let publishOneMsg = publishOneMsg' chan args
50 inotify <- initINotify
56 (handleEvent publishOneMsg (suffix args))
57 hr $ "watching " ++ (inputFile args)
58 _ <- forever $ threadDelay 1000000
61 hr $ "sending " ++ (inputFile args)
62 messageFile <- BL.readFile (inputFile args)
64 then mapM_ (publishOneMsg Nothing) (BL.lines messageFile)
65 else publishOneMsg (Just (inputFile args)) messageFile)
66 (\exception -> printparam' "exception" $ show (exception :: X.SomeException))
67 -- all done. wait and close.
69 then waitForConfirms chan >>= return . show >> return ()
73 -- | The handler for publisher confirms
74 confirmCallback :: (Word64, Bool, AckType) -> IO ()
75 confirmCallback (deliveryTag, isAll, ackType) =
78 ((show deliveryTag) ++
84 -- | Hotfolder event handler
86 (Maybe String -> BL.ByteString -> IO ()) -> [String] -> Event -> IO ()
87 -- just handle closewrite and movedin events
88 handleEvent f s (Closed False (Just x) True) = handleFile f s x
89 handleEvent f s (MovedIn False x _) = handleFile f s x
90 handleEvent _ _ _ = return ()
92 -- | Hotfolder file handler
94 (Maybe String -> BL.ByteString -> IO ()) -> [String] -> FilePath -> IO ()
95 handleFile _ _ ('.':_) = return () -- ignore hidden files
96 handleFile f s@(_:_) x =
97 if any (flip isSuffixOf x) s
98 then handleFile f [] x
102 (hr ("sending " ++ x) >> BL.readFile x >>= f (Just x))
104 printparam' "exception in handleFile" $
105 show (exception :: X.SomeException))
107 -- | Publish one message with our settings
108 publishOneMsg' :: Channel -> Args -> Maybe String -> BL.ByteString -> IO ()
109 publishOneMsg' c a fn f = do
110 (mtype, mencoding) <-
111 if (magic a) && isJust fn
113 m <- magicOpen [MagicMimeType]
115 t <- magicFile m (fromJust fn)
116 magicSetFlags m [MagicMimeEncoding]
117 e <- magicFile m (fromJust fn)
118 return (Just (T.pack t), Just (T.pack e))
119 else return ((contenttype a), (contentencoding a))
120 now <- getCurrentTime >>= return . floor . utcTimeToPOSIXSeconds
124 (T.pack $ currentExchange a)
128 , msgDeliveryMode = persistent a
129 , msgTimestamp = Just now
131 , msgType = msgtype a
132 , msgUserID = userid a
133 , msgApplicationID = appid a
134 , msgClusterID = clusterid a
135 , msgContentType = mtype
136 , msgContentEncoding = mencoding
137 , msgReplyTo = replyto a
138 , msgPriority = prio a
139 , msgCorrelationID = corrid a
140 , msgExpiration = msgexp a
141 , msgHeaders = substheader (fnheader a) fn $ msgheader a
143 printparam "sent" $ fmap show r
146 [String] -> Maybe String -> Maybe FieldTable -> Maybe FieldTable
147 substheader (s:r) (Just fname) old =
148 substheader r (Just fname) (addheader old (s ++ "=" ++ fname))
149 substheader _ _ old = old