--- Log opened Thu Sep 17 00:00:38 2009
09:38 < kristofer> morning
09:38 < mightybyte> Morning
09:41 < kristofer> how can I split up the appstate into data models in different files?
09:42 < mightybyte> Using happstack's state system?
09:42 < kristofer> yeah
09:42 < mightybyte> As far as I know, you can't.
09:42 < mightybyte> What you can do is put things into separate components.
09:44 < mightybyte> But different components will still get stored in the same state files on disk.
09:50 < kristofer> I'm not concerned about the data store.. more like grouping the model with functions in a file instead of putting all of state in a single file
09:50 < mightybyte> Ohhh, at the source code level?
09:50 < kristofer> yeah
09:51 < mightybyte> Oh, there is a lot of flexibility there.
09:51 < kristofer> I'm not very experienced with haskell, so I apologize if it's pretty novice
09:51 < mightybyte> Well, basically you have all of haskell's modularity capabilities to work with.
09:52 < mightybyte> My state is spread around quite a number of source files.
09:52 < mightybyte> Let's say you have a state like this:
09:52 < kristofer> what's confusing me then is this: $(mkMethods ''AppState ['getTimeCard, 'addTimeStampEntry])
09:53 < mightybyte> data AppState = AppState [(Key, Value)]
09:53 < kristofer> so I could feasibly import all the data models, and then okay
09:53 < kristofer> sorry, continue
09:53 < mightybyte> That mkMethods call builds the query/update operations on your state.  getTimeCard and addTimeStampEntry are just haskell functions that operate on the state.
09:54 < mightybyte> Yes, you're on the right track.
09:54 < mightybyte> Those functions can be declared anywhere.
09:54 < mightybyte> You just have to import them into the file where you have the mkMethods call.
09:54 < kristofer> so I'd need to let AppState know about all the functions from other models though.. I could not run that line of code at the end of each model to let the parent object know what's up
09:54 < kristofer> ?
09:54 < mightybyte> Similarly, in my example, Key and Value can be defined in other files and imported.
09:55 < kristofer> okay
09:55 < mightybyte> Right
09:55 < mightybyte> But that's pretty much just a simple import.
09:58 < kristofer> alright, if my TimeCard model is in another file imported by my AppState, how does the TimeCard know about AppState and how to make it aware of the new functions?
10:01 < mightybyte> TimeCard shouldn't know about AppState
10:01 < kristofer> okay
10:01 < mightybyte> Otherwise you'll get a cyclic dependency.
10:02 < mightybyte> ghc will give you an error
10:02 < mightybyte> I think there is a way to get cyclic dependencies to compile, but I've never bothered to figure out how.
10:02 < kristofer> yeah, I was wondering if there were some parent-child relationship between the two
10:02 < mightybyte> Yes, you probably want a clear parent-child relationship.
10:32 < stepcut> dons: I have a Strict ByteString which I want to convert to a Lazy ByteString. But, I also want to drop the first 'n' bytes of the ByteString. Is it better to do, L.drop n (L.fromChunks [strictByteString]), or L.fromChunks [S.drop n strictByteString]
10:34 < dons> the second, i think
10:34 < lambdabot> dons: You have 1 new message. '/msg lambdabot @messages' to read it.
10:36 < stepcut> dons: ah right. I thought that, S.drop n strictByteString, would make a whole copy, but now I remember that the BS construct includes an offset parameter, so it will just tweak the offset
10:39 < dons> that's right
10:44 < stepcut> this new file serve library is shaping up
10:44 < stepcut> the old one was full of wackiness
10:44 < mightybyte> Yeah
10:44 < mightybyte> It's never been important enough for me to do anything about.
10:45 < mightybyte> Alhtough I've wished you didn't have to specify all the allowed files by name.
10:45 < stepcut> it had a feature where you can request a file, "foo.c,bar.c" and if that file does not exist, but "foo.c" and "bar.c" do, it will concat them together and serve them as a single file. Is that some standard I have never heard of before? Or something supported by other servers?
10:45 < stepcut> mightybyte: you don't have to specify all the allowed files by  name..
10:45 < mightybyte> lol, I've never heard of it.
10:46 < mightybyte> You don't?  That's the first arugment.
10:47 < stepcut> no. the first argue is the list of index files. ie. the files it should look if you request a directory instead of a specific file
10:47 < stepcut> like, index.html
10:47 < mightybyte> Oh, heh.
10:47 < stepcut> if you request, http://example.com/foo/ and foo/index.html exists, it will serve that file
10:48 < mightybyte> I think I'm listing all my served files there.
10:48 < stepcut> :)
10:48 < mightybyte> Hah, that's funny.
10:48 < stepcut> well, if a users requests the directory it will serve the first file in that list that it finds
10:49 < stepcut> on the otherhand, I just wrote a function for my coworker yesterday which makes it so you do have to explicitly list all the files you want to serve :)
10:49 < mightybyte> Heh
10:50 < mightybyte> That functionality also makes sense at times.
10:50 < stepcut> actually, it will be more general. You supply a function (FilePath -> Failing FilePath), which transforms the incoming filename to the name of the file on disk, or fails
10:50 < stepcut> or perhaps it will be, (MonadIO m) => (FilePath -> m (Failing FilePath))
10:51 < mightybyte> Yeah, I could see a use for the monadic version.
10:51 < stepcut> and then you could have a, whilelist :: [FilePath] -> (FilePath -> m (Failing FilePath)), function or whatever else you want
10:51 < stepcut> it's useful to have the name of the files on disk be different than the name of the file in the request
10:52 < mightybyte> Yeah
10:52 < stepcut> it also useful to be able to specify the mime-type explicitly, and not just rely on the filename extension
10:52 < mightybyte> Definitely
10:53 < stepcut> so the new version has underlying functions where you specify all that stuff, and then higher level functions that do it automatically in different ways
10:53 < mightybyte> Great
10:53 < stepcut> you might do it by extension, you might do it using libmagic, or you might look it up in your database because you recorded the mime-type at upload time
10:54 < stepcut> also have the ability to serve files with an offset from the beginning
10:55 < stepcut> you can serve anything using sendfile that is accessible via a Handle. You can also serve content that can be converted to a Strict ByteString  or Lazy ByteString
10:55 < stepcut> for files, you could use any of those three methods.
10:56 < mightybyte> Sounds great
10:56 < stepcut> also, you can completely override the default mime-type map or default index file lists
10:57 < stepcut> and there is a function to serve a single file
10:58 < stepcut> so you could do, dir "site.css" $ serveFileUsing filePathSendFile "text/css" "/usr/share/mysite/foo.css"
11:00 < stepcut> the function names need a bit of work, but I am going to clean that up after all the features are complete
11:00 < dcoutts> stepcut: for serving the contents of tarballs I also want to be able to serve segments of file, preferably without leaking file handles
11:00 < dcoutts> I look up the offset of the file within the tar file (using a pre-generated index)
11:01 < dcoutts> and seek and read the right length
11:01 < stepcut> dcoutts: yeah, that should be easy to do. There is a function,
11:01 < stepcut> -- |use sendfile to send the contents of a Handle
11:01 < stepcut> sendfileResponse :: String  -- ^ content-type string
11:02 < stepcut>                  -> Handle  -- ^ file handle for content to send
11:02 < dcoutts> it makes management easier than unpacking the tar file and using the file system
11:02 < stepcut>                  -> Maybe CalendarTime -- ^ mod-time for the handle (MUST NOT be later than server's time of message origination)
11:02 < stepcut>                  -> Integer -- ^ offset into Handle
11:02 < stepcut>                  -> Integer -- ^ number of bytes to send
11:02 < stepcut>                  -> Request -- ^ incoming request (used to check for if-modified-since)
11:02 < stepcut>                  -> Response
11:02 < dcoutts> ok, nice
11:02 < stepcut> not sure if it leaks Handles though :-/
11:02 < dcoutts> stepcut: it's just hGetContents that would do
11:02 < dcoutts> if the file is not read to the end
11:03 < stepcut> dcoutts: if sendfile closes the handle, then all should be good.
11:03 < dcoutts> right
11:03 < dcoutts> does response now embody an action for putting to the output handle?
11:03 < dcoutts> Response type I mean
11:03 < stepcut> yes
11:04 < dcoutts> ok, nice
11:04 < dcoutts> with a wrapper for the simple ByteString case
11:04 < stepcut> the Response type now has two constructors: Response { .. } and SendFile { .. }
11:04 < dcoutts> ah
11:04 < stepcut> Response is the Lazy ByteString case
11:04 < dcoutts> Couldn't you do with just one constructor?
11:04 < stepcut> and SendFile is the Handle case
11:05 < stepcut> dcoutts: dunno, what are you thinking ?
11:05 < dcoutts> hmm, I guess the Response lets you modify the ByteString with a filter
11:05 < dcoutts> like gzip
11:06 < dcoutts> stepcut: I was thinking if the raw thing is just Handle -> IO (), then that covers output both by send file and by hPutStr theByteString
11:06 < stepcut> http://patch-tag.com/r/happstack/snapshot/current/content/pretty/happstack-server/src/Happstack/Server/HTTP/Types.hs
11:06 < stepcut> that is the current definition
11:06 < dcoutts> but of course Response lets you modify the ByteString
11:07 < stepcut> dcoutts: mae wrote it, so he might know
11:07 < dcoutts> stepcut: my first impression is that the SendFile case is too special, with offset etc
11:07 < stepcut> yeah
11:07 < dcoutts> that it should be just sfDoIt :: Handle -> IO ()
11:07 < stepcut> though, my new FileServe library also allows offsets when serving ByteStrings
11:08 < dcoutts> and you would construct one using sendFile ::  ... -> SendFile, that insets a call to the raw_sendfile as the sfDoIt member
11:08 < dcoutts> ah, the sfHandle is the Handle to send *from*
11:09 < dcoutts> I'm thinking of the Handle to send to
11:09 < dcoutts> the output sink
11:09 < stepcut> yeah, the Handle is what you send from
11:10 < dcoutts> so I think it could be more general by giving access to the output sink
11:10 < dcoutts> even if that's not made accessible publicly
11:10 < dcoutts> there's more scope for smart constructors
11:12 < stepcut> well, personally I think the whole thing should be replaced with hyena, so.. ;)
11:12 < dcoutts> heh heh
11:12 < dcoutts> is that tibbe's http server?
11:12 < stepcut> yeah
11:12 < stepcut> based on iteratees
11:13 < dcoutts> mm, he's got some good ideas
11:13 < dcoutts> I'm not sure the full blown iteratees model is lovely however
11:13 < stepcut> you don't have to worry about leaking file handles, etc
11:13 < dcoutts> I think it can probably be a little more lightweight, but I've not looked too closely
11:14 < stepcut> I wrote a little happstack+hyena demo a while back, http://src.seereason.com/examples/happstack-hyena-tutorial/Hyena.html
11:15 < stepcut> alas, there is no 'next section'
11:21 < dcoutts> so much fun stuff to do, so little time
11:21 < stepcut> indeed
11:22 < stepcut> sweet! I think the new code does more and is 100 lines shorter
12:11 < aavogt> stepcut: on that Hyena demo, you import > import Happstack.Server.Cron (cron)
12:11 < aavogt> but I can only find Happstack.Util.Cron
12:12 < aavogt> are there some different versions of happstack-server that supply Cron?
12:14 < stepcut> aavogt: it was moved to Happstack.Util.Cron, that demo is out of date
12:14 < stepcut> the cron stuff is not vital anyway
12:15 < stepcut> it just does a checkpoint every 24 hours
12:15 < stepcut> you are not likely to let the demo run that long :)
12:16 < aavogt> yeah, that's the same as a forkIO $ forever (threadDelay milisecondsInADay >> createcheckPoint ctl)
12:16 < aavogt> right?
12:16 < stepcut> almost
12:17 < stepcut> threadDelay is limited to delays of less than ~35 minutes
12:17 < stepcut> so it has some hackery to get around that
12:18 < stepcut> http://patch-tag.com/r/happstack/snapshot/current/content/pretty/happstack-util/src/Happstack/Util/Cron.hs
12:25 < aavogt> interesting
15:48  * stepcut wonders if the buildbot still runs
16:02 < stepcut> pushed a significant patch to FileServe
16:02 < stepcut> hope I didn't break nothin'
16:13 < burp> somehow all haskell database api's are horrible
16:13 < mightybyte> Heh, that's why *we* are here. :)
16:20 < jmcarthur_work> takusen is okay
16:21 < stepcut> burp: maybe it's because what they are binding to is horrible
16:22 < burp> ;-)
18:00 < dons> did anyone try happstack state restoration with the new binary version?
--- Log closed Fri Sep 18 00:00:40 2009