3
$\begingroup$

Actually related question 127248. But in that post, the answer from Kuba suggest provide a URL for API-user. But I still hope the API can output the file into the local disk directly. Is it possible?

As the Kuba's comment, the browser cannot write the local disk otherwise it will lead to malicious scripts overflow. But as I know the browser has some ability to write data into disk, such as those video or web-page cache file.

I mean:

FormPage[{"FileNames" -> <|"Interpreter" -> "String", 
    "Hint" -> "File names copy from Excel"|>, 
  "Directory" -> <|"Interpreter" -> "String", 
    "Hint" -> 
     "Specify a directory to download"|>}, (URLDownload[{#FileNames}, \
#Directory]) &, AppearanceRules -> <|"Title" -> "Test API"|>, 
 PageTheme -> "Blue"]

It will download https://i.stack.imgur.com/VULeb.png into my directory E:\document. But if I use CloudDeploy to deploy an API:

CloudDeploy[
 FormPage[{"FileNames" -> <|"Interpreter" -> "String", 
     "Hint" -> "File names copy from Excel"|>, 
   "Directory" -> <|"Interpreter" -> "String", 
     "Hint" -> 
      "Specify a directory to download"|>}, \
(URLDownload[{#FileNames}, #Directory]) &, 
  AppearanceRules -> <|"Title" -> "Test API"|>, 
  PageTheme -> "Blue"], "DownFiles", Permissions -> "Public"]

It cannot into local disk download anymore. How to implement it? If the browser cannot write the data into the E:\document but just can write into some cache directory, I also will accept the way..

$\endgroup$
5
  • $\begingroup$ As you already mentioned, ordinary browsers won't allow what you want. One final (but highly dangerous) thing to try is building your own browser on top of the Chromium Project. That way, you should be able to customize every aspects of your browser. (Needless to say, you should avoid using it for daily usage.) $\endgroup$
    – Silvia
    Apr 27, 2019 at 14:59
  • $\begingroup$ You can't specify where it downloads, but you can download all the files to the default Downloads folder on your friend's machine by returning the appropriate MIMEType for the result. $\endgroup$
    – b3m2a1
    Apr 29, 2019 at 16:33
  • $\begingroup$ Will you have multiple files or just a single file? The single file solution is somewhat easier, but both will be possible. $\endgroup$
    – b3m2a1
    Apr 29, 2019 at 16:45
  • $\begingroup$ @b3m2a1 Multiple files, actually 100+... Could you give further explanation for your solution? $\endgroup$
    – yode
    Apr 29, 2019 at 17:37
  • $\begingroup$ @yode I'm thinking basically have your API create a ZIP archive of the files. Then push that to a CloudObject with the right MIMEType and then return the URL to that via HTTPRedirect $\endgroup$
    – b3m2a1
    May 1, 2019 at 19:31

1 Answer 1

4
+50
$\begingroup$

You can use the channel framework to communicate between your local session and the cloud api you deploy. First create a channel listener with public permissions in your local session:

channel = ChannelListen["test", Permissions -> "Public"]

Next get the hard coded URL to deploy with your api:

In[54]:= channel["URL"]

Out[54]= "https://channelbroker.wolframcloud.com/users/[email protected]/test"

Using this URL, deploy your api function:

CloudDeploy@FormPage[
    {"FileNames"-><|"Interpreter"->"String","Hint"->"File names copy from Excel"|>,"Directory"-><|"Interpreter"->"String","Hint"->"Specify a directory to download"|>}
    ,
    URLRead@
        URLBuild["https://channelbroker.wolframcloud.com/users/[email protected]/test",
            {
                "operation"->"send",
                "Message"->ToString@<|"FileNames"->{#FileNames},"Directory"->#Directory|>
            }]&
    ,
    AppearanceRules-><|"Title"->"Test API"|>,
    PageTheme->"Blue"
]

When receiving the message, use ToExpression to turn the result into an association you can easily work with:

In[53]:= Dynamic@ToExpression@channel["Message"]
Out[53]= <|Message-><|FileNames->{BAR},Directory->BAZ|>|>

Now all that is left to do is make the local session trigger a URLDownload with the parameters sent via your channel. Take a look at the documentation for ChannelListen for many more examples.

$\endgroup$
6
  • $\begingroup$ Hi, I want build the API for those friend without mathematica to downlaod image bulk. But your solution seem to use Dynamic@ToExpression@channel["Message"] to receive the url? BTW, I get a Missing[NotAvailable]. What I have missed? $\endgroup$
    – yode
    Apr 28, 2019 at 6:26
  • $\begingroup$ Ah, I see what you're saying, this is just a good way to make the cloud api communicate with a local Mathematica session.. I am not sure how to accomplish what you want to do, I will think about it more. $\endgroup$ Apr 29, 2019 at 15:19
  • $\begingroup$ Thank, anyway.. $\endgroup$
    – yode
    Apr 29, 2019 at 17:38
  • $\begingroup$ I can't help but think I don't deserve the bounty as I did not answer your question. You didn't even accept my answer.. how does this work? $\endgroup$ May 7, 2019 at 17:45
  • $\begingroup$ I don't want to waste the bounty. And I feel appreciative for your work still, though I have not accept it. :) $\endgroup$
    – yode
    May 7, 2019 at 18:00

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.