Using nakama storage for user uploaded images

Hello folks, I wanted to pick your brain on a decision I have to make around image uploads. I have private rooms all set up and working with nakama. My game involves uploading multiple images before starting the game. These images will likely be large as they can come from the user’s gallery (expect most users to be mobile users). I found this thread which seems relevant and aligns with what I had in mind.

Currently, I’m base64’ing the string on my client and using nakama client to upload those images directly to the nakama storage. The problem is that the image has no validation or pre-processing yet. Ideally, I would like to do this from the server side (probably with a custom rpc) where I can receive the image, pre-process it, bucket it to the right collection, and then store it. The current approach only works with small images, I expect to handle 15 photos per private room which will eventually increase. I wanted to get your thoughts on this. My only experience storing images has been using a S3 buckets, so I’m not sure if storing it in a base64 string is a good practice or not. I also considered storing these images directly on memory and storing a path-to-image on the database but I worry this might get too expensive in the long term.

Thanks!

  1. Versions: Nakama {3.5}, {Windows, Mac, Linux binary or Docker}, {client library (SDK) and version}
  2. Server Framework Runtime language (If relevant) {Go, TS/JS, Lua}
{code or log snippet}

:tv: Media:

Hi @rpparede,

As Andrei mentioned in the thread you linked to, you can certainly store base64 encoded images in the Nakama Storage engine. Though you should consider placing appropriate file size limitations. I would also recommend using an RPC as you’ve mentioned to authoritatively process the image before storing (verify it is an image etc etc).

The alternative of course would be to use a dedicated image storage service for this instead and then store the URL for the image in Nakama storage. This would come with the benefit of the service provider doing all of the validation for you.

Thanks for the reply @tom . I’m trying to implement the RPC way. However I’m kinda stuck in getting this to work.
I figured that calling the RPC function directly from the socket does not work, I was trying to pass the body to the RPC without success.
await ctx.client.rpc(ctx.session, rpcid, {“image”:images});

I’m now making a POST request using fetch that lets me send the body to the RPC and receive it on the backend. I’m currently using a FormData to append all the images I need to send to the server after the user uploads them. I’m then sending the form data in the body of the request as follows:

fetch('http://127.0.0.1:7350/v2/rpc/image-upload?http_key=defaulthttpkey&unwrap', {
  method: 'POST',
  body: data,
  headers: {
     'Content-type': 'multipart/form-data',
  },

})

However, I keep running into unmarshalling errors on the go lang backend. I’m also not sure if nakama rpc handles multipart/form-data transfers. In the docs I only saw json being passed around.

Could you please provide an example if possible on how to submit multiple (<1GB) images to the RPC endpoint. It would be much appreciated. Thanks!

You need to ensure you’re base 64 encoding the images as a string and then pass the payload as a JSON string. For example, the payload should look something like:

{
  "images": [
    "aGVsbG8=",
    "d29ybGQ="
  ]
}

Note: We don’t support multipart/form-data content via RPC.

I would advise using the standard client.rpc() function and passing the payload as a string as intended.

Thanks for the answer @tom, can this be also done using gRPC streaming possibly?
I had to override the yaml configs to accept large messages. I worry this approach seems very hacky or it may open a door for performance issues in the future.
local.yml
name: nakama-node-1
data_dir: “./data/”
socket:
max_message_size_bytes: 1000000
max_request_size_bytes: 1000000
read_buffer_size_bytes: 1000000
write_buffer_size_bytes: 1000000
cluster:
max_message_size_bytes: 1000000
console:
max_message_size_bytes: 1000000

I’m not aware of anyone using the realtime socket in this way, so I would need to know more about how you have implemented this to comment. Again, if your images are very large I would definitely recommend using a dedicated image hosting service rather than storing them in the Nakama storage engine.