Permalink
Browse files

initial import

  • Loading branch information...
0 parents commit ac1d9b00d115f7272ba45328ac9a50618c0fa9bc @mariusae committed Jul 17, 2010
Showing with 164 additions and 0 deletions.
  1. +25 −0 LICENSE
  2. +23 −0 README.md
  3. +8 −0 Web/TwitterStream.hs
  4. +61 −0 Web/TwitterStream/Iteratee.hs
  5. +7 −0 Web/TwitterStream/Types.hs
  6. +22 −0 stream.hs
  7. +18 −0 twitterstream.cabal
25 LICENSE
@@ -0,0 +1,25 @@
+Copyright (c) 2010 marius a. eriksen (marius@monkey.org)
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+1. Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+2. Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+3. The names of the authors may not be used to endorse or promote products
+ derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS OR
+IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY DIRECT,
+INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
+IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGE.
@@ -0,0 +1,23 @@
+# Twitter Streaming for Haskell
+
+An interface ot the
+[Twitter streaming API](http://dev.twitter.com/pages/streaming_api)
+for Haskell. The status objects are of the same type as those in
+[hs-twitter](http://hackage.haskell.org/package/hs-twitter).
+
+The library provides an iteratee to extract status objects from a
+stream of characters as well as a driver to stream HTTP respones. This
+allows for a simple and efficient interface:
+
+ import qualified Web.TwitterStream as Stream
+ ...
+
+ Stream.driver (Stream.BasicAuth "user" "pass") Stream.Sample $ do
+ status <- Stream.status
+ case status of
+ Just status -> do something...
+ Nothing -> parse fail..
+
+Build via cabal:
+
+ cabal configure && cabal build
@@ -0,0 +1,8 @@
+module Web.TwitterStream
+ ( module Web.TwitterStream.Types
+ , module Web.TwitterStream.Iteratee
+ ) where
+
+import Web.TwitterStream.Types
+import Web.TwitterStream.Iteratee
+
@@ -0,0 +1,61 @@
+module Web.TwitterStream.Iteratee
+ ( driver
+ , status
+ ) where
+
+import Prelude hiding (catch)
+import Control.Monad.IO.Class
+import Control.Concurrent.MVar (newMVar, modifyMVar_)
+import Control.Exception (catch, SomeException(..))
+
+-- for the JSON instance:
+import qualified Web.Twitter.Types.Import as TwitterTypes
+import qualified Data.Iteratee as Iter
+import Data.Iteratee.Char (line)
+import qualified Network.Curl as Curl
+import Web.Twitter.Types (Status(..))
+import Text.JSON (decode, Result(..))
+
+import Web.TwitterStream.Types
+
+url Sample = "http://stream.twitter.com/1/statuses/sample.json"
+url Firehose = "http://stream.twitter.com/1/statuses/firehose.json"
+
+driver :: Auth -> Stream -> Iter.IterateeG [] Char IO a -> IO ()
+driver (BasicAuth username password) stream iter' = Curl.withCurlDo $ do
+ iter <- newMVar iter'
+
+ let recvChunk chunk = modifyMVar_ iter $ \iter -> do
+ cont <- Iter.runIter iter (Iter.Chunk $ chunk)
+ case cont of
+ -- TODO - actually handle the cases here.
+ Iter.Done x _ -> return iter
+ Iter.Cont next _ -> return next
+
+ h <- Curl.initialize
+ Curl.setopts h
+ [ Curl.CurlFailOnError True
+ , Curl.CurlURL $ url stream
+ , Curl.CurlUserPwd $ username ++ ":" ++ password
+ , Curl.CurlHttpAuth [Curl.HttpAuthAny]
+ , Curl.CurlWriteFunction $ Curl.callbackWriter recvChunk
+ ]
+
+ Curl.perform h
+ return ()
+
+status :: (Monad m, MonadIO m) => Iter.IterateeG [] Char m (Maybe Status)
+status = do
+ l <- line
+ case l of
+ Left _ -> return Nothing
+ Right l ->
+ return =<< liftIO $
+ catch (decodeStatus l)
+ (const $ return Nothing :: SomeException -> IO (Maybe Status))
+
+ where
+ decodeStatus line = do
+ case decode line of
+ Ok status -> return $ Just status
+ Error _ -> return Nothing
@@ -0,0 +1,7 @@
+module Web.TwitterStream.Types
+ ( Auth(..)
+ , Stream(..)
+ ) where
+
+data Auth = BasicAuth String String -- username, password
+data Stream = Sample | Firehose
@@ -0,0 +1,22 @@
+module Main where
+
+import Control.Monad.IO.Class
+import System (getArgs)
+import Web.Twitter.Types (Status(..))
+
+import qualified Web.TwitterStream as Stream
+import qualified Data.Iteratee as Iter
+
+main = do
+ u : p : _ <- getArgs
+
+ Stream.driver (Stream.BasicAuth u p) Stream.Sample tweets
+
+ where
+ tweets = do
+ s <- Stream.status
+ case s of
+ Just s -> (liftIO $ f s) >> tweets
+ Nothing -> tweets
+
+ f tweet = putStrLn $ statusText tweet
@@ -0,0 +1,18 @@
+cabal-version: >= 1.6
+name: twitterstream
+version: 1.0
+build-type: Simple
+license: BSD3
+license-file: LICENSE
+author: marius a. eriksen
+category: Web
+synopsis: Haskell interface for the Twitter Streaming API
+maintainer: marius a. eriksen
+copyright: (c) 2010 marius a. eriksen
+
+library
+ build-depends:
+ base == 4.*, iteratee >= 0.3.4, hs-twitter >= 0.2.8,
+ json >= 0.4.3, curl >= 1.3.5, transformers >= 0.2
+ exposed-modules:
+ Web.TwitterStream

0 comments on commit ac1d9b0

Please sign in to comment.