Fork me on GitHub
#clojure
<
2024-02-26
>
itaied12:02:36

clojure aws integrations - how can I invoke a Lambda? I'm trying

(aws/invoke lambda {:op :InvokeWithResponseStream
                      :request {:FunctionName "my-lambda"
                                :Payload {:k "v"}}})
=> 
; Execution error (IllegalArgumentException) at cognitect.aws.util/eval16987$fn$G (util.clj:145).
; No implementation of method: :->bbuf of protocol: #'cognitect.aws.util/BBuffable found for class: clojure.lang.PersistentArrayMap

(aws/invoke lambda {:op :InvokeWithResponseStream
                      :request {:FunctionName "my-lambda"
                                :Payload (json/write-str {:k "v"})}})
=>
:cognitect.anomalies/category :cognitect.anomalies/fault, :cognitect.aws.client.impl/throwable #error {
 :cause "No matching clause: 0"
deps:
com.cognitect.aws/api            {:mvn/version "0.8.692"}
             com.cognitect.aws/endpoints      {:mvn/version "1.1.12.504"}
             com.cognitect.aws/lambda         {:mvn/version "848.2.1413.0"}
             org.clojure/data.json            {:mvn/version "2.5.0"}

itaied18:02:38

It seems like the lib parse the response and expects a json, though it's an array. how can I disable the json deserializing?

itaied18:02:47

yep, looking at the meta response i can see the correct result. Does anyone has experience with invoking lambdas using this lib?

emccue17:02:49

Would anyone be interested in a string templating library wrapping/mimicking the design of java string templates?

(<< StringTemplate/STR "Hello ~{name}")
(<< Html/HTML
    "
    
~(for [i (range 10)] (<< Html/HTML "Hello ~{i}"))
")
I.E. each template needs an explicit template processor specified and might not produce a string as a result + can do validation

Noah Bogart17:02:18

how do you see it working? what would be the difference between this and other templating engines/formatting functions?

emccue17:02:59

Well, the way it works in java is that a template processor gets two lists. A list of fragments and a list of values. It is assumed that you get 1 more fragment than values

emccue17:02:38

then the template processor does whatever it wants - so like escaping html values or replacing parameters in sql queries with ?s

Noah Bogart17:02:30

woah, that's java?

emccue17:02:51

so here i wrote one that takes in a Connection and its a template processor which can make a prepared statement

emccue17:02:06

and one which is just a constant, but can produce properly escaped html

emccue17:02:33

the benefit of this design over plain string templating is that you need to say STR."Hello \{name}" for "normal" strings

emccue17:02:00

so you always need to confront "should I be just string appending or escaping values"

Noah Bogart17:02:17

that's pretty cool. I've never seen that syntax before. I don't know if I'd ever use it, but I'd enjoy reading the code if you made this a library lol

emccue17:02:39

i would just need to rip apart clojure.core.incubator.strint

emccue17:02:58

or whatever the name of the library with the << is

emccue17:02:22

> I've never seen that syntax before. This is all "preview" java, so not stable features until 23 probably

👍 1
Noah Bogart17:02:25

aha, that explains it.

Noah Bogart17:02:28

yeah, this is cool

emccue17:02:20

its interesting because nothing really prevented this design in clojure

emccue17:02:50

but the design of "you must specify a processor" falls out of concerns about the corpus of "code in the world" and how humans behave

emccue17:02:11

which i don't think is the top priority of macro writers always so...interesting

Noah Bogart17:02:45

that makes sense

doug kirk01:02:08

The Java syntax and semantic for string templates is borrowed from Scala, which has had it for nearly 10 years now. 🙂 It amounts to a lightweight DSL over java.text.MessageFormat

emccue05:02:03

> borrowed from Scala, which has had it for nearly 10 years now. I think that you can argue that the s" prefix for "regular string interpolation" might be a bit too short for the goal of "make people think twice about whether regular string interpolation is appropriate" that STR. has. Which is fun - clunkiness being legitimately used in language design design.

eraserhd17:02:16

Hi, I'm having an issue with an old server's socket REPL dying almost immediately with the error, Exception in thread "Clojure Server repl" java.net.SocketTimeoutException: Accept timed out. Does this sound familiar to anyone?

eraserhd17:02:35

I see JDK issues that suggest this could happen if run with a profiler on older an older JDK, and we have a live profiler connected. We're on Clojure 1.10.2.

3starblaze18:02:04

Hey, I'd really appreciate if someone could give me some pointers (no pun intended) on how to do this. There is a C header I want to integrate. The problem is that the header does not define any functions, only typedefs. So how does this work? Godot calls C lib that I have built with some pointers, the main one being p_get_proc_address which is used to obtain a function which then can be called. I tried using dtype-next but I don't think there's a way to call the function with dtype-next. I've looked into JNA, it seems like com.sun.jna.Function with Function(Pointer functionAddress, int callFlags, java.lang.String encoding) constructor could do the job. Does it mean that I have to work with JNA via interop? After some reading I read that there are some definitions to be made but if we don't count some enums, there's nothing really to define. Since I'm not too familiar with the Java ecosystem, I'd appreciate any help with this. My plan is to start JVM in C and then pass those function pointers to Clojure so that I can interact with Godot via this pointer. To have a better idea on what I want to achieve, here's an example how this stuff will work. Pay attention to p_get_proc_address.

c
#include <stdio.h>
#include "godot-headers/gdextension_interface.h"

void noop(void *userdata, GDExtensionInitializationLevel p_level) {
  return;
}

// Make sure you open godot from console in order to see these printf's
// also you should be at Godot 4.1+ afaik
GDExtensionBool
godot_entry(
  GDExtensionInterfaceGetProcAddress p_get_proc_address,
  const GDExtensionClassLibraryPtr p_library,
  GDExtensionInitialization *r_initialization
) {
  printf("hello from godot_entry!\n");
  printf("I obtained %p!\n", p_get_proc_address);
  printf("I obtained %p!\n", p_library);
  printf("I obtained %p!\n", r_initialization);

  printf("prep\n");

  GDExtensionGodotVersion version_info;
  GDExtensionInterfaceGetGodotVersion get_godot_version
    = (GDExtensionInterfaceGetGodotVersion)p_get_proc_address("get_godot_version");
  get_godot_version(&version_info);

  printf("Godot Version info:\n");
  printf("  major: %i\n", version_info.major);
  printf("  minor: %i\n", version_info.minor);
  printf("  patch: %i\n", version_info.patch);
  printf("  str: %s\n", version_info.string);

  // These functions have to be initialized to prevent crashing
  r_initialization->initialize = noop;
  r_initialization->deinitialize = noop;

  return 1;
}
This is how the function looks like in the header file.
// ...
/**
 * @name get_godot_version
 * @since 4.1
 *
 * Gets the Godot version that the GDExtension was loaded into.
 *
 * @param r_godot_version A pointer to the structure to write the version information into.
 */
typedef void (*GDExtensionInterfaceGetGodotVersion)(GDExtensionGodotVersion *r_godot_version);
// ...

phronmophobic18:02:32

I think there's more than one way to do it depending on your goals. As long as you're calling functions that follow the c ABI, then you can use JNA. Since dtype-next supports JNA, you can also use dtype-next if you want. Another option is to use graalvm's native image. You can either create a shared library that is consumed from some c++ code or make C ABI calls into native code (similar to JNA).

phronmophobic19:02:00

Starting the JVM from C is possible, but I've found it's often easier to call into C code from the JVM, but it depends on your goals.

phronmophobic19:02:47

Oh, just read a bit more about GDExtension. If you want to make an extension with clojure, then I think your best bet is to compile a shared library using graalvm's native image.

3starblaze19:02:31

dtype-next doesn't have a way to call function via pointer and I don't think that the stuff that is passed around is JNA-compatible. I didn't want to use GraalVM because I wanted to make a base version of the library with JVM. I don't have a good understanding of Java ecosystem and considered GraalVM to be additional complexity at this stage. I probably would try to incorporate GraalVM at some point. I think JNA is the answer, I probably just need to rest a bit and do some more research on how to use JNA. Thanks for the help!

phronmophobic19:02:51

I'm not that familiar with godot or GDExtension, but it describes itself as: > GDExtension is a Godot-specific technology that lets the engine interact with native shared libraries at run-time. You can use it to run native code without compiling it with the engine. If you want the end result to be a shared library, then I'm not aware of an easier option than graalvm's native image which specifically targets that use case.

3starblaze19:02:34

If GraalVM provides an easier way than JVM, I'll give it a try. My idea was to make a tiny C glue library that startups JVM and passes the pointer to some Clojure function which can then start initialization and let the library user call Godot main API's functions. If I use GraalVM, would that mean I won't need that glue layer?

phronmophobic19:02:13

Unfortunately, you probably will. You still need to do some initialization in native code, before calling into the shared library.

3starblaze19:02:55

Then how exactly GraalVM would help me in this situation? I know it has its own benefits but it doesn't seem like it would make much difference in gluing together Clojure with C.

phronmophobic19:02:13

Graalvm provides a recipe for creating shared or static libraries. The only other alternative I'm aware of would be to jni invocation API, https://docs.oracle.com/en/java/javase/11/docs/specs/jni/invocation.html. Is that what you're planning on using?

phronmophobic20:02:13

Or are you planning on starting a JVM application, that application somehow starts the godot engine, which eventually calls back into the JVM application?

3starblaze20:02:22

JNI Invocation is the option I am planning to use. Everything starts when Godot project is opened, it calls the shared library and I use this moment to start JVM and pass the function pointer.

phronmophobic20:02:36

Yea, that could work. If you're trying to deploy this extension, I imagine it will be much, much larger than a graalvm native version, but it depends on what the extension is used for.

phronmophobic20:02:59

You'll also have to deal with the class path and startup time issues, but maybe that's not a big deal for your use case.

3starblaze20:02:24

Right now I'm focusing on a proof of concept. The library should be able to provide access to Godot as if it was a normal Clojure library. Eventually I would want to bundle the glue layer and Clojure code alongside the game so it works on other devices.

3starblaze20:02:05

GraalVM seems like a great use case for this but, as I've mentioned before, I want to focus on proof-of-concept and try not to bring extra stuff until I have the main idea going.

👍 1
phronmophobic20:02:27

Sounds neat! I'm sure there are folks in #C066UV2MV that might be interested to hear how it goes.

3starblaze20:02:54

Thanks! About 3 years ago there was godotclj which ended up dead but some people definitely had interest in the library. I used to do a little bit of work there but ended up being a bit overwhelmed about how all the pieces fit together. Now I am making this as qualification work for university so I'm fairly certain that eventually something usable should emerge from this project.

clojure-spin 1
phronmophobic20:02:00

It seems like embedding Godot as a shared library would also be an interesting option, but it's not quite ready yet, https://github.com/godotengine/godot-proposals/issues/6267

👍 1
emccue22:02:17

@U02S4QZAH61 Maybe also look at the coffi stuff

emccue22:02:36

initializing the jvm/making those stubs would be an open issue

emccue22:02:46

but there is support for upcalls and whatnot