Fork me on GitHub
#beginners
<
2021-12-05
>
Andrew Byala06:12:56

I need to create an anonymous function that returns the or of two other predicates on a single input. I've come up with two ways to represent this, and they do both work, but I suspect there's a simpler representation I can't find. Any thoughts?

#(or (pred1 %) (pred2 %))
#(some (fn [pred] (pred %)) [pred1 pred2])

Andrew Byala07:12:24

Of course it's that simple! Thanks, @U04V4KLKC!

(some-fn pred1 pred2)

Jakub Zika07:12:32

Hi, how would you call this in Clojure?

Storage.SignUrlOption.httpMethod(HttpMethod.PUT)
from: https://github.com/googleapis/java-storage/blob/main/google-cloud-storage/src/main/java/com/google/cloud/storage/Storage.java#L64 Thank you

hiredman08:12:07

Find a java example, and translate it into clojure

Jakub Zika08:12:46

This is the java example

import com.google.cloud.storage.BlobId;
import com.google.cloud.storage.BlobInfo;
import com.google.cloud.storage.HttpMethod;
import com.google.cloud.storage.Storage;
import com.google.cloud.storage.StorageException;
import com.google.cloud.storage.StorageOptions;
import java.net.URL;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.TimeUnit;

public class GenerateV4PutObjectSignedUrl {
  /**
   * Signing a URL requires Credentials which implement ServiceAccountSigner. These can be set
   * explicitly using the Storage.SignUrlOption.signWith(ServiceAccountSigner) option. If you don't,
   * you could also pass a service account signer to StorageOptions, i.e.
   * StorageOptions().newBuilder().setCredentials(ServiceAccountSignerCredentials). In this example,
   * neither of these options are used, which means the following code only works when the
   * credentials are defined via the environment variable GOOGLE_APPLICATION_CREDENTIALS, and those
   * credentials are authorized to sign a URL. See the documentation for Storage.signUrl for more
   * details.
   */
  public static void generateV4GPutObjectSignedUrl(
      String projectId, String bucketName, String objectName) throws StorageException {
    // String projectId = "my-project-id";
    // String bucketName = "my-bucket";
    // String objectName = "my-object";

    Storage storage = StorageOptions.newBuilder().setProjectId(projectId).build().getService();

    // Define Resource
    BlobInfo blobInfo = BlobInfo.newBuilder(BlobId.of(bucketName, objectName)).build();

    // Generate Signed URL
    Map<String, String> extensionHeaders = new HashMap<>();
    extensionHeaders.put("Content-Type", "application/octet-stream");

    URL url =
        storage.signUrl(
            blobInfo,
            15,
            TimeUnit.MINUTES,
            Storage.SignUrlOption.httpMethod(HttpMethod.PUT),
            Storage.SignUrlOption.withExtHeaders(extensionHeaders),
            Storage.SignUrlOption.withV4Signature());

    System.out.println("Generated PUT signed URL:");
    System.out.println(url);
    System.out.println("You can use this URL with any user agent, for example:");
    System.out.println(
        "curl -X PUT -H 'Content-Type: application/octet-stream' --upload-file my-file '"
            + url
            + "'");
  }
}

Jakub Zika08:12:06

I am fighting with the url part You can see my last try..

(defn generate-v4-gput-object-signed-url [project-id bucket-name object-name]
  (let [storage (-> (StorageOptions/newBuilder) (.setProjectId project-id).build .getService)
        blob-info (-> (BlobInfo/newBuilder
                       (BlobId/of bucket-name object-name))
                      .build)
        extension-headers (-> (HashMap.)
                              (.put "Content-Type" "application/octet-stream"))
        url ((.signUrl storage blob-info 15 (TimeUnit/MINUTES)
                       ;;  doesn't work
                       (.httpMethod com.google.cloud.storage.Storage$SignUrlOption (HttpMethod/PUT))
                       (.withExtHeaders com.google.cloud.storage.Storage$SignUrlOption extension-headers)
                       (.withV4Signature com.google.cloud.storage.Storage$SignUrlOption)))]
    (println "Generated PUT signed URL:")
    (println url)
    (println "You can use this URL with any user agent, for example:")
    (println (str "curl -X PUT -H 'Content-Type: application/octet-stream' --upload-file my-file '"
                  url
                  "'"))))

hiredman08:12:40

That example is from the same project, so it can access package Private classes

Jakub Zika08:12:31

How should i call static function which is in class inside interface?

hiredman08:12:40

The sign url option class is package private, so the expectation is you don't interact with it directly, so I would find some java examples of using the library

hiredman08:12:00

And do whatever they do, because they won't be using package private stuff directly

hiredman08:12:02

Ah, interesting, the class is package private, but it has a public static method

👍 1
hiredman08:12:34

You are definitely not calling a static method

hiredman08:12:59

Maybe checkout the docs on java interop for calling a static method

hiredman08:12:42

But I am not entirely sure the clojure compiler will be happy about a package private class with a public static method

hiredman08:12:28

https://clojure.org/reference/java_interop#_member_access has examples of what static method calls look like

Jakub Zika08:12:51

Yeah, I already tried both (.staticfn class) and (class/staticfn)

hiredman08:12:46

You have the class name correct, but are trying to invoke a method named httpMethod on the Class object

hiredman08:12:33

You also have an extra set of parens where you at invoking the result of signUrl as a function

hiredman08:12:51

You'll also need to check out the section on the interop page about varargs

Jakub Zika08:12:58

Yeah, this is the result of messing with the code trying to solve it…

Jakub Zika08:12:38

My biggest problem is how to call static function on nested class…. I though that by Storage$SignUrlOption I should be able to access the inner class and then I call its static function

hiredman08:12:59

Possibly, but the code you shared is broken, and not calling a static method at all, and you haven't shared details of the error messages you got, so I cannot assess if you had a syntax or there was some other problem

hiredman08:12:19

It sounds to me like maybe you weren't calling the static method correctly (the way you are describing it, accessing the inner class then calling static methods on it, doesn't in my mind match the syntax of calling a static method)

hiredman08:12:19

The syntax is just (theclassname/themethodname arg1 arg2 etc) so (Storage$SignUrlOptiom/httpMethod HttpMethod/PUT)

👍 1
hiredman08:12:56

If you did have the syntax of the static method call correct, the error you are hitting might just be the varargs not being correct, but I dunno what error you got

Jakub Zika08:12:08

You are right, thx. I just checked the history and it was (Storage/httpMethod …)

Jakub Zika08:12:32

Now I am getting varargs error, finally 🙂 This is the first time i have needed to call a class inside interface

hiredman08:12:00

Clojure's java interop would be better named jvm interop, because every place java and the jvm differ, clojure exposes the jvms version

👁️ 2
hiredman08:12:37

varargs and inner classes are two places where java and the jvm differ

👍 1
Jakub Zika08:12:01

Would you recommend some text about details maybe? The clojure <-> java and especially clojure <-> other jvm languages interop is not my strong skill

hiredman08:12:30

I don't know of one

clojure-spin 1
hiredman08:12:31

Inner classes aren't a jvm thing, they are just normal class files, with names created by concatenating the enclosing class and the inner classes name separated by a $

hiredman08:12:38

Varargs don't exist on the jvm, they just methods that take a trailing array argument

Jakub Zika09:12:49

Good info.. This is the updated and working 1:1 code if anybody is interested…

(defn generate-v4-gput-object-signed-url [project-id bucket-name object-name]
  (let [storage (-> (StorageOptions/newBuilder) (.setProjectId project-id) .build .getService)
        blob-info (-> (BlobInfo/newBuilder
                       (BlobId/of bucket-name object-name))
                      .build)
        extension-headers (doto (HashMap.)
                            (.put "Content-Type" "application/octet-stream"))
        url (.signUrl storage blob-info 15 (TimeUnit/MINUTES)
                      (into-array [(com.google.cloud.storage.Storage$SignUrlOption/httpMethod HttpMethod/PUT)
                                   (com.google.cloud.storage.Storage$SignUrlOption/withExtHeaders extension-headers)
                                   (com.google.cloud.storage.Storage$SignUrlOption/withV4Signature)]))]
    (println "Generated PUT signed URL:")
    (println url)
    (println "You can use this URL with any user agent, for example:")
    (println (str "curl -X PUT -H 'Content-Type: application/octet-stream' --upload-file my-file '"
                  url
                  "'"))))

👍 2
Benjamin17:12:51

I guess making requests with http-kit for example doesn't already do retry logic e.g. when 429 or whatever it is is returned?

sova-soars-the-sora19:12:52

Http-kit does not do range-queries unfortunately

sova-soars-the-sora19:12:58

(unrelated but something else that it could use)

sova-soars-the-sora19:12:12

492... "too many requests" ... what behavior do you want? long-poll retry?

Benjamin07:12:43

https://developer.atlassian.com/cloud/jira/platform/rate-limiting/ I was reading this. Incremental backof I guess. Don't know about long polling

Cora (she/her)20:12:04

courier is a thing that'll handle a lot of interesting http client use cases https://github.com/cjohansen/courier

👀 1
Cora (she/her)20:12:23

things like retries, caching, inter-request dependencies