Showing progress status in file upload handler (handleMultiPart) in Snap Framework - haskell

I am using Snap framework to prototype a web application. I am trying to use Snap.Util.FileUploads.handleMultiPart to upload a file, immediately process it using iteratee, and at the same time display the progress message on the same page.
It is possible to hook Data.Enumerator.printChunks to debug progress on the console. I could not figure out how to display the progress on the same page while processing the file upload. How can a progress message be displayed using handleMultiPart during file upload?
Also handleMultiPart takes PartInfo -> Iteratee ByteString IO a to handle the file upload. Should handleMultiPart rather take MonadIO m => PartInfo -> Iteratee ByteString m a to make it simpler?

In general I don't know if it's possible to display progress on the client side via pushing an HTML response while the file is being uploaded. To the best of my knowledge, web apps that do this are typically using some JavaScript API or Flash widget to do so. Certainly it's not possible using handleMultiPart.
Streaming to the console is another matter, however -- you can easily provide an enumeratee that logs chunk information (or updates an MVar, for an alternative) and then passes control downstream. This will be less brain-bending in snap 1.0 (nearing release), which will use io-streams which are much easier to think about.
Finally, handleMultiPart works over IO because to do otherwise would require the "run" action for the monad, i.e the inverse lift from (m a -> IO a). There are ways to do this kind of thing but snap <1.0 doesn't do them, sorry --- and in snap 1.0 the issue will be moot.

Related

Read in file with client-side clojurescript/re-frame app

I'm writing a client-side application which should read in a file, transform its content and then export the result. To do this, I decided on Re-Frame.
Now, I'm just starting to wrap my head around Re-Frame and cloujurescipt itself and got the following thing to work:
Somewhere in my view functions, I send this whenever a new file gets selected via a simple HTML input.
[:input {:class "file-input" :type "file"
:on-change #(re-frame/dispatch
[::events/file-name-change (-> % .-target .-value)])}]
What I get is something like C:\fakepath\file-name.txt, with fakepath actually being part of it.
My event handler currently only splits the name and saves the file name to which my input above is subscribed to display the selected file.
(re-frame/reg-event-db
::file-name-change
(fn [db [_ new-name]]
(assoc db :file-name (last (split new-name #"\\")))))
Additionally I want to read in the file to later process it locally. Assuming I'd just change my on-change action and the event handler to do this instead, how would I do it?
I've searched for a while but found next to nothing. The only things that came up where other frameworks and such, but I don't want to introduce a new dependency for each and every new problem.
I'm assuming you want to do everything in the client using HTML5 APIs (eg. no actual upload to a server).
This guide from MDN may come handy: https://developer.mozilla.org/en-US/docs/Web/API/File/Using_files_from_web_applications
It seems you can subscribe to the event triggered when the user selects the file(s), then you can obtain a list of said files, and inspect the files contents through the File API: https://developer.mozilla.org/en-US/docs/Web/API/File
In your case, you'll need to save a reference to the FileList object from the event somewhere, and re-use it later.

Haskell, Yesod and Keter - How can I run a routine periodically (every 5 minutes)?

There are some database queries I want to run periodically, and according to its state, send notifications to users email and change the state of their accounts. Can I do it within Yesod itself?
I moved from Yesod's issue.
Run Handler code at a specific time within yesod · Issue #1529 · yesodweb/yesod
I do not know your complete code.
So, this is proposal.
makeApplication :: App -> IO Application
makeApplication foundation = do
unsafeHandler foundation $
forkHandler (\_ -> catchError) $ forever $ do -- catchError do not exist
waitUntil10AM -- waitUntil10AM do not exist
getCheckupR
logWare <- makeLogWare foundation
-- Create the WAI application and apply middlewares
appPlain <- toWaiAppPlain foundation
return $ logWare $ (acceptOverride . autohead . gzip def) appPlain
This code point that use unsafeHandler and forkHandler.
waitUntil10AM
I do not know your timezone, environment, database structure etc, so I want you to write the details yourself.
For example, if you put threadDelay in forever and check it once every ten minutes, put the date on which you sent the mail already in the database and call it if you do not send it and it exceeds 10AM.
catchError
Please decide what kind of processing should be done at the time of error.
I would like to handle errors in a way that it would never stop
You can name the function to be passed inside forkHandler and call it again on error.

How to return unescaped response in Snap web application

I want to return some preformatted html in a snap application. However, when the handler below is served,
aPage :: Handler App App ()
aPage = do
writeText "<p>This is a page</p>"
The output is couched in < pre > tags.
...<body><pre><p>This is a page</p></pre></body> ...
Is there a simple way to add a verbatim string to the response body?
You don't.
As Carl pointed out in the comment to my question, it was not "escaped" to begin with. What I was seeing was the browsers rendition of the plaintext document. Simply sending a properly formatted document gives me what I was expecting.
aPage :: Handler App App ()
aPage = do
writeText "<!DOCTYPE html><html><head></head><body><p>This is a page</p></body></html>"
After fiddling with Blaze-html and Lucid, two libraries for generating html, I was sure some sort of formatting was going on under the hood and thought some sort of toHtmlRaw function was needed. Not at all the answer I was expecting.

Haskell Servant and streaming

I am trying to add a functionality to my servant server that would get a file from Amazon S3 and stream it back to the user.
Because files can be big I don't want to download them locally and then serve them to clients, I'd rather prefer to stream them directly from S3 to clients.
I use Amazonka for what I do with S3 and I can get a stream for an S3 file as a Conduit sink.
But now I don't know how to get from Sink to EitherT ServantErr IO a.
Can anyone explain me how to do it or show me some example of how it can be done?
The is nothing in Servant to do this out of the box, however all the needed parts are available.
Before we begin, I guess that if you can stream to a Sink, that means you have a source (the gorsBody of GetObjectResponse is a RsBody, which is a Source)
First of all, Servant provides us with the possibility to add support for new return types, by creating a new instance of HasServer, so we could serve a EitherT ServantErr IO (Source ...) and have it stream.
To create that instance, we must implement route :: Proxy layout -> Server layout -> RoutingApplication. Server layout, in this case, just means EitherT ServantErr IO layout, layout being the source we want to server, so it's the function that returns a source (and may fail with an HTTP error).
We have to return a RoutingApplication, which is (in continuation style) a function that takes a Request and returns a RouteResult Response, which means either an unmatched route error, or a response. Both Request and Response are standard wai, not Servant, so we can now look at the rest of the ecosystem to find how to implement it.
Fortunately, we don't have to go far: Network.Wai.Conduit contains just what we need to implement the route function: responseSource takes a status value, some response headers and your source and gives you a Response.
So, that is quite a lot of work to do, but everything we need is there. Looking a the source of the instance HasServer * (Get ...) might help.

HappStack event files

I am developing a game and chose Happstack for the persistence part. I find it quite easy to use, i made a quick example for myself to understand it:
getAllObjects :: MonadIO m => m [Thing]
getAllObjects = do
elems <- query GetObjects
return elems
addAnObject :: (MonadIO m) => Thing -> m ()
addAnObject thing = do update $ AddObject thing
test command = do
control <- startSystemState macidProxy
result <- command
shutdownSystem control
return result
checkpoint = do
control <- startSystemState macidProxy
createCheckpoint control
shutdownSystem control
and everytime i 'test' it, it create an event.file. then i 'checkpoint' and creates a new checkpoint file, it is ok for me, the problem is that the old events files keep growing! i manualy delete everyfile (except last checkpoint and current).
Is there some code im missing from happstack to do the 'delete old things'?
There is no built-in mechanism for purging old event files. Lemmih has talked about adding such facilities to acid-state at some point in time.
EDIT: The darcs version of acid-state now has a function 'createArchive' to archive old log files that are no longer needed to restore the current state.

Resources