01:44:57 <stepcut> i'm thinking you already know the hostname and port, so constructing the url version should be easy?
10:48:23 <rlpowell> What's the oldest GHC y'all think I could do current happstack work with?
11:01:22 <KBme> hello again …
11:01:54 <KBme> does anyone know why my state would not overlap between MonadPlus instances?
11:02:07 <KBme> I'm using msum for my routing
11:02:17 <KBme> and have a state monad for my application state
11:03:25 <KBme> so I do msum [do put something; mzero, dir "foo" >> get something]
11:03:50 <KBme> it seems the put runs in a different state than the get and I can't get my environment
11:04:17 <KBme> I hope the explanation can be understood …
11:05:46 <KBme> this is for implementing login functionality
11:06:18 <KBme> at the very beginning of the msum list I have the applet that checks whether the user has a session, if so it adds the session to the state
11:06:50 <KBme> then I want to use this session, but it doesn't work as expected from an other line of the msum…
11:08:26 <KBme> so for routes I have msum [initsession, usesession]
11:08:47 <KBme> and usesession doesn't have access to the same state as initsession
11:11:00 <donri> rlpowell: i think 7.0 is the oldest supported
11:11:51 <rlpowell> *nod*
11:11:56 <donri> but we don't have a ci testing that for every release currently
11:12:56 <donri> also you need at least 7.2 for the (optional) generics support i added to web-routes
11:13:33 <donri> but you can use web-routes-th on 7.0
11:16:04 <donri> KBme: how about, initsession >> msum [usesession, ...]
11:16:38 <KBme> donri, I bet that works since I already do initialization before calling the msum and that part is common for all the monads in the msum
11:17:23 <donri> note that msum isn't really magical, it just makes a serverpart, so you can nest them etc
11:17:31 <KBme> is there no way to make the monads inside the msum have access to the same state? is msum evaluated in parallel or something?
11:17:34 <KBme> aaaah
11:17:38 <KBme> gotcha
11:17:44 <KBme> but still
11:18:32 <donri> what you are asking for is mutable state and yes you can have that with IOVar/MVar/TVar
11:18:41 <donri> but you don't need that here
11:18:47 <KBme> IF i have msum [do authapp.initsession; msum [authapp.route1, …], otherapp.route1…]
11:18:56 <KBme> otherapp will not have access to that environment?
11:19:22 <donri> no app does in that case ...
11:19:41 <donri> unless you go mutable
11:19:45 <KBme> ah
11:19:48 <KBme> ok
11:20:01 <KBme> do you know where I can find good documentation for doing this?
11:21:04 <donri> just do simpleHTTP ... $ msum [ things not using session, do initSession; msum [ things using session ] ]
11:21:23 <donri> it's all composable! yay!
11:22:06 <KBme> right …
11:22:14 <KBme> ah well, I guess that could work for now
11:22:42 <KBme> donri, but is it simple to migrate from a statemonad to something that uses IOVar/MVar/TVar?
11:23:19 <KBme> if not it might be worth it to migrate now, before it's used in a lot of places …
11:23:26 <KBme> anyways, thanks donri
11:23:35 <donri> also what are you doing in initsession? maybe you really want a reader instead
11:24:29 <donri> so instead of initsession you do runReaderT
11:24:31 <KBme> initsession reads a cookie, checks if a session exists and populates a field in my state record
11:24:58 <KBme> hmm
11:25:00 <donri> also maybe look at happstack-clientsession
11:25:05 <KBme> so make session a readermonad …
11:25:14 <KBme> I have, it doesn't seem to do what I need
11:25:57 <donri> are you doing serverside sessions?
11:26:14 <donri> with just an ID in the cookie
11:26:17 <KBme> yep
11:28:05 <donri> that's more difficult than it first appears, mind you
11:28:26 <donri> e.g. how to prune old sessions
11:28:38 <KBme> I just expire them at midnight
11:28:44 <donri> heh ok
11:28:55 <KBme> then one can have a cron job that deletes them from the database
11:29:29 <KBme> but I guess one could also update a lastSeen timestamp and expire after 48 hours of inactivity or stuff like that
11:30:04 <donri> are you storing the sessions in acid-state?
11:30:30 <KBme> nah, i'm using postgresql for storage
11:30:43 <KBme> hough I could use acid-state for the sessions
11:31:04 <KBme> but since I already use postgresql, I decided to simply use postgresql for everything
11:32:53 <donri> hm then i'm not sure since queries are going to be more expensive
11:33:14 <KBme> right
11:33:22 <KBme> which is why I just expire them at midnight
11:34:47 <donri> with acid-state i would just not bother with initsession and just do things like, sessID <- getSessionID; update $ LogOut sessID, aka, update . LogOut =<< getSessID, possibly have helper functions for that
11:34:57 <donri> where getSessionID just reads the cookie
11:37:14 <donri> actually with postgres you actually want initsession even less since that'll always read the session, for every request, and presumably also write it after the request finishes, regardless of whether the request uses the session
11:37:39 <donri> that's what happstack-clientsession does, what makes it a bit complicated, because it avoids decrypting/encrypting the session cookie unnecessarily
11:38:04 <donri> you could look at how it does that and just substitute the cookie crypting with postgre queries
11:38:55 <KBme> ok
11:39:08 <donri> on the other hand this is kind of the sort of thing where acid-state really does make sense so maybe just use it for sessions only?
11:39:28 <KBme> yeah, I could do that
11:39:42 <KBme> is acid-state on-disk, or only in-memory?
11:39:51 <KBme> ACTION looks
11:39:59 <donri> it is kept in memory but logged to disk for persistence
11:40:23 <donri> if you're pruning on midnight anyway maybe you don't care about persistence and you could just use a TVar (or the memory backend in acid-state, but that doesn't really give you much over a TVar)
11:40:34 <KBme> but it isn't that bad to read the session for every request, since I need that info.
11:41:04 <KBme> well, having all the sessions in the memory can be a bit much imho…?
11:41:26 <donri> if you have many sessions and not so much memory that may be so yes
11:41:36 <donri> could always use clientsession ;)
11:41:59 <donri> handles all this for you with no memory and no db queries
11:42:06 <KBme> huh
11:42:09 <KBme> how? files?
11:42:17 <donri> it's stored in a cookie
11:42:20 <donri> encrypted
11:42:30 <KBme> oh
11:42:32 <donri> so you can't have too much data in there
11:42:35 <KBme> mh dunno
11:42:43 <donri> but often you don't need much data in the session anyway
11:43:12 <donri> it uses SafeCopy so you can have any data structure you want in the session more or less
11:43:13 <KBme> but then I have to get the user info anyways
11:44:19 <donri> normally you'd store a user ID in the clientsession and look that up as needed, yea
11:45:08 <donri> although if you're just doing things like, get the full name of the user ID to display in the UI, you could just store that in a normal, unencrypted cookie
11:48:26 <KBme> yeah, but that takes a lot of extra bookkeeping
11:58:10 <KBme> donri, if initsession also might return a response, how would you modify this?
11:59:02 <KBme> what initsession does is IF user is authenticated, it callse mzero, otherwise it renders a login form
12:02:04 <donri> not sure what you're asking
12:02:22 <donri> if you do like i said and don't use msum it's a non-issue, unless i'm misunderstanding you
12:04:48 <donri> do loggedIn <- getLoggedIn; if loggedIn then do initSession; msum sessionHandlers else seeOther LoginPage
12:05:53 <donri> don't think of msum as syntax for simpleHTTP. it's just a function, and you can use it inside any handler, nest them, etc etc
12:07:36 <KBme> yeah, that's fine, but it's weird that the different monads in the list supplied to msum don't get the same state
12:07:43 <donri> so the above code makes a handler that itself further dispatches to the sessionHandlers
12:08:25 <KBme> that was the reason I started using a statemonad, really
12:08:32 <donri> nah it's not weird :) MonadPlus makes a dispatch tree, not a list of handlers to run in sequence
12:08:34 <KBme> to have a state common to my app
12:08:39 <KBme> ok
12:08:39 <donri> msum taking a list is just incidental
12:09:05 <KBme> and if I want that, I have to use a mutable state
12:09:27 <KBme> which I guess is the same as a statemonad but uses an MVar or something?
12:09:28 <donri> or just monad bind before msum like i said
12:09:36 <KBme> yeah
12:09:39 <KBme> ok
12:09:51 <KBme> i'll take a look at MVar/TVar etc
12:10:02 <donri> you don't want mutable state for this
12:10:14 <donri> these are not the droids you're looking for
12:10:19 <KBme> heh
12:11:19 <KBme> so then i would do
12:12:38 <KBme> do sth ← initSession; if sth == mzero then do msum [..] else ok $ sth
12:13:06 <donri> can't check for mzero that way i'm afraid
12:13:37 <KBme> thought so ☺
12:13:46 <KBme> guh
12:13:51 <donri> maybe you want finishWith?
12:14:01 <KBme> hm
12:14:07 <donri> or actually
12:14:09 <KBme> probably not ☺
12:14:31 <KBme> maybe I need to initSession to return a Maybe Response then
12:14:54 <donri> or just do this all in one handler like i suggested
12:14:57 <KBme> because I had made the function with the thought that all members in the msum will have access to the same state
12:15:10 <donri> or pass in the msum part to initSession
12:15:36 <donri> simpleHTTP $ msum [ ..., withSession $ msum [...] ]
12:15:43 <KBme> yeah, i need to rethink the architecture of this thing with this in mind
12:16:06 <KBme> that the state will not be shared between different monads in the list supplied to msum
12:16:41 <KBme> ACTION thought he'd get away with it simply ;)
12:16:46 <KBme>  ◕ ‿ ◕
12:17:09 <donri> it is simple, you're just stuck in an assumption about how to do it ;)
12:17:33 <KBme> well, yeah
12:17:50 <KBme> it would've been soooooooo simple and elegant 😜
12:18:01 <donri> it's arguably a case of haskell preventing you from doing something bad. most of the time you *don't* want handlers to affect each other that way
12:18:16 <KBme> well, I guess so
12:19:05 <donri> aka. routing here is "pure"
12:19:18 <donri> YOU LIKE PURITY DON'T YOU? *stern look*
12:22:42 <KBme> heh
12:22:44 <KBme> I do
12:23:48 <KBme> but it takes a lot of fighting with it
12:27:26 <cizra> Curious. Why is there no configuration option, in happstack server, for file uploads? Right now I'm getting this message: “Reached disk quota of 0 bytes.” and I can't figure out how to fix this.
12:28:39 <KBme> it's in bodypolicy
12:28:45 <KBme> the crash course explains it
12:29:44 <KBme> cizra, http://www.happstack.com/docs/crashcourse/RqData.html#bodypolicy
12:29:52 <cizra> Ahhh!
12:29:56 <cizra> yeah, I can Google
12:30:17 <cizra> Of course. “maximum bytes for files uploaded in this Request”
12:30:22 <KBme> yep
12:31:25 <cizra> \o/
12:31:43 <KBme> \😜/
12:32:16 <cizra> haha
12:36:49 <donri> cizra: happstack-lite and happstack-foundation handle that for you though
12:36:59 <donri> also hi :)
12:37:03 <donri> si coi
12:37:33 <cizra> Hi :-) How do they handle it?
12:38:56 <cizra> Also, I have happstack-foundation installed, but I'm following the lite tutorial, but compiling against regular happstack-server (as lite wasn't included in the Debian packages (which I tried first (but then got rid of)))
12:39:11 <cizra> .. if that matters.
12:39:38 <KBme> ACTION wonders what foundation is
12:40:06 <KBme> ah, got it
12:42:19 <cizra> ACTION read through the Lite tutorial. I feel I understand the intent of all the code, if not some specifics. I would like to try and port this application to use web-routes.
12:53:55 <cizra> How do I pretty-print HTML with blaze?
12:54:24 <cizra> Namely, how do I change the renderer?
12:54:28 <cizra> Text.Blaze.Html.Renderer.Pretty
12:59:36 <donri> cizra: you can't change how toResponse renders it but you can make a newtype wrapper or render it manually with a helper function
13:00:08 <donri> easier just install a browser plugin like view source chart though :)
13:01:01 <cizra> I was just wondering why Firefox is slow to switch to my happstack app and back, compared to other tabs.
13:01:11 <cizra> Maybe it doesn't like the one-line-fits-all approach.
13:03:19 <donri> shouldn't matter
13:03:23 <donri> i think google does that for example
13:07:57 <cizra> Well, what matters then?
13:08:12 <cizra> There is no Javascript, there is no stylesheet. It's just the example tutorial page thingy.
13:25:07 <cizra> Erh. I can't figure out how to do this :( I'm trying to change the renderer by hiding on import and overriding everything related to ToMessage, but I get an error about type synonyms.
13:25:21 <cizra>     Illegal instance declaration for `ToMessage Html'
13:25:21 <cizra>       (All instance types must be of the form (T t1 ... tn)
13:25:21 <cizra>        where T is not a synonym.
13:26:40 <hpaste> bla pasted “bl” at http://hpaste.org/78759
13:26:45 <cizra> ^ that
15:15:31 <donri> cizra: yea you need a LANGUAGE TypeSynonymInstances pragma
15:16:03 <donri> i think the error message informs you of that
15:16:41 <cizra> It does. I thought I don't really need it, somehow.. That I'm doing it wrong and TypoSynonymInstances pragma is a workaround. Hm.
15:17:11 <donri> well Html is a type synonym for, i think, MarkupM ()
15:17:29 <donri> which means you may also need FlexibleInstances
15:18:04 <cizra> hmhm
15:18:06 <donri> but i don't think you can make your own instance for ToMessage Html since there's no way to import ToMessage without getting that instance
15:19:39 <donri> so you could newtype PrettyHtml = PrettyHtml Html, or just make a Html -> Response function without using toMessage
15:19:41 <donri> uh toResponse
15:22:32 <cizra> ACTION sighs
15:23:36 <stepkut> this is why I don't like ToMessage.. but I have never come up with a better idea
15:24:55 <donri> i don't think it's a real problem. this is what newtypes are good for :)
15:25:25 <donri> but otherwise maybe we could have a way to register renderers... seems overkill to me though
15:35:39 <cizra> Hmmhmm
15:36:01 <cizra> > import Happstack.Server.SimpleHTTP hiding (ToMessage(..))
15:36:03 <lambdabot>   <hint>:1:1: parse error on input `import'
15:36:28 <cizra> then > import qualified Text.Blaze.Html.Renderer.Pretty   as Blaze
15:36:37 <stepkut> you can't hide class instances
15:36:38 <cizra> Then copy-pasted > class ToMessage a where
15:36:50 <donri> stepkut: he's replacing the class itself
15:36:52 <cizra> then copy-pasted the instances
15:36:58 <donri> cizra: you don't gain anything doing that
15:37:02 <cizra> (two turned out to be necessary)
15:37:14 <cizra> Aaaand that's it, now it works.
15:37:28 <donri> really the only point to ToMessage is that happstack calls it for you if you return a value whose type is an instance, in a handler
15:37:45 <cizra> I'm not proficient enough in Haskell, especially type classes and stuff, but at least it prints it pretty now.
15:37:45 <donri> it can't do that with your replacement class
15:37:54 <cizra> Now, what was the elegant solution again? :-)
15:38:04 <donri> so if you're doing that you may as well do a plain function :)
15:41:43 <cizra> Hmm, so what am I supposed to do now? Import hiding the toMessage function, then reimplement it?
15:42:09 <stepkut> how about, prettyHtmlResponse :: Html -> Response
15:42:20 <stepkut> ok $ prettyHtmlResponse $ yourHtml
15:42:35 <stepkut> where prettyHtmlResponse uses toResponseBS
15:49:04 <cizra> Hah, cool. Now it pretty-prints it all right, but the Content-Type header is text/plain, which renders the HTML source as text :-D
15:49:23 <stepkut> :)
15:50:12 <donri> yea that's what you need toResponseBS for
15:50:20 <donri> @hoogle toResponseBs +happstack-server
15:50:20 <lambdabot> Could not find some databases: happstack-server
15:50:21 <lambdabot> Searching in:
15:50:21 <lambdabot>   .
15:50:24 <donri> :(
15:50:28 <donri> brb
15:50:59 <cizra> Why BS? Blaze.renderHtml produces a String, not BS.
15:54:54 <stepkut> hmm
15:55:58 <cizra> Anyhow, I'm using toMessage, but it doesn't set the right content-type.
15:56:04 <cizra> > prettyHtmlResponse h = toResponse . Blaze.renderHtml $ h
15:56:06 <lambdabot>   <hint>:1:22: parse error on input `='
15:56:21 <cizra> So apparently the wrong instance of ToMessage is used.
15:57:56 <stepkut> no.. that is using the instance for String which assumse text/plain
16:03:45 <stepkut> everything eventually has to be converted to a ByteString so it can be sent over the network
16:04:58 <stepkut> why do you want it pretty anyway?
16:14:35 <cizra> Oh, the original intent was to check if Firefox parses it faster, but then I thought it'd be nice for debugging.
16:14:55 <cizra> It wasn't any faster, by the way. Still slow as .. something slow. Why? The page is as plain as it can be!
16:33:51 <donri> cizra: do you have assets for that page like css or js? are you compiling with -threaded and running with +RTS -N?
16:35:16 <donri> happstack's server is the slowest in haskell, which just means it serves 9000 requests per second instead of 50 000 ;)
16:35:42 <stepkut> we should fix that :p
16:35:45 <donri> :)
16:35:53 <cizra> donri: No css, no js, no -threaded, no +RTS -N. The slowness comes not from loading the page, but switching tabs!
16:36:09 <cizra> Actually I run it in ghci
16:36:20 <donri> sounds like browser bug o_O have you tried another browser?
16:36:26 <cizra> nope
16:36:46 <cizra> Curious! It's fast now!
16:36:50 <donri> :D
16:36:57 <cizra> What changed? Hmmm
16:37:16 <cizra> Nothing. Nothing changed, yet Firefox switches tabs fast now.
16:38:33 <donri> note that ghci is interpreted and ghc isn't really optimized for that so it's much (much) slower than a proper compilation
16:38:44 <donri> but usually still fast enough that you don't notice, for things like this
16:39:24 <cizra> Yeah
16:51:45 <KBme> is there a way to use a  (ServerPartT IO) a StateMonad outside of happstack?
16:52:05 <KBme> I want to create a commandline tool for testing some functions, so I need an IO () type
16:52:39 <stepkut> one moment
16:53:05 <KBme> I use runStateT but it still has type (ServerPartT IO) a …
16:53:22 <donri> you can use simpleHTTP' i think it was to "run" a ServerPart
16:53:39 <KBme> oh
16:53:43 <stepkut> http://hub.darcs.net/stepcut/happstack/browse/happstack-server/tests/Happstack/Server/Tests.hs
16:53:45 <KBme> checking the docs …
16:53:50 <donri> simpleHTTP'' :: (ToMessage b, Monad m, Functor m) => ServerPartT m b -> Request -> m Response
16:53:53 <donri> two primes :)
16:53:57 <KBme> even better: some code ☺
16:54:12 <stepkut> lines 121 and 148
16:55:12 <KBme> hmmm
16:55:34 <KBme> I don't really need a request, I just want to test some database code that's tied into my StateMonad type
16:56:13 <donri> well if there's a serverpart in there you need to give it a request
16:56:28 <donri> or refactor out your database state stuff
16:56:34 <KBme> right
16:56:57 <KBme> it would be prettier if I just used IO for the db stuff and ServerPartT IO for the rest
16:56:59 <KBme> ah well
16:57:22 <stepkut> if your type requires ServerPartT .. then you need to provide some sort of Request .. even if you don't actually use it
16:57:53 <KBme> all right, I need mkRequest and simpleHTTP'' I guess
16:57:56 <donri> there's a bunch of stuff that's going to look at the request, even if *you* aren't
16:58:01 <KBme> ACTION looks for mkrequest
16:58:10 <KBme> yep, gotcha
16:58:15 <donri> there is no mkRequest, you'll have to copy it from stepkut's link
16:58:28 <KBme> I would need to embed the database (IO) stuff into the ServerPartT IO stuff
16:58:41 <KBme> yep
16:58:43 <donri> i think we should make this easier in hs8
16:59:35 <donri> stepkut: also would it be possible to make Request IO-free without a big performance cost?
17:00:19 <stepkut> donri: not in the current code
17:00:24 <donri> like, have the stuff that's currently MVars be Pipes or something
17:00:32 <donri> i'm talking about happstack 8 here
17:01:39 <KBme> you guys should always use qualified imports … it's so much easier to read … 😜
17:01:46 <donri> hm although one reason to make it IO-free might be so you could serialize requests... and having pipes in there don't make that any easier i don't think
17:01:53 <stepkut> donri: line 64, http://hub.darcs.net/stepcut/hyperdrive/browse/pipes-http-7/Types.hs
17:02:07 <donri> stepkut: (you can link lines on hub)
17:02:15 <donri> http://hub.darcs.net/stepcut/hyperdrive/browse/pipes-http-7/Types.hs#64
17:02:18 <stepkut> \o/
17:02:39 <donri> ah cool, that looks nice and pure
17:03:48 <donri> although Response has a Pipe in there, so you couldn't serialize that (e.g. for caching) AFAIK?
17:18:26 <dsfox> https://www.pivotaltracker.com/story/show/40627961
17:19:12 <stepkut> :-/
17:20:14 <donri> why are you linking us this?
17:20:32 <donri> it's a login page btw :)
18:00:03 <cizra> Are there any websites written with happstack available for stealing ideas from? :-)
18:01:12 <cizra> Hmm, googling helped :-)
18:07:53 <stepkut> :)
23:50:12 <donri> would anyone object to me adding instances for unordered-containers to safecopy? it introduces two currently non-platform dependencies, although somewhat ubiquitous ones
23:51:11 <donri> vector might be a good candidate also, and it's already in platform