Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Option to add http/https agent of my own. #28

Closed
adame21 opened this issue Mar 9, 2021 · 8 comments
Closed

Option to add http/https agent of my own. #28

adame21 opened this issue Mar 9, 2021 · 8 comments

Comments

@adame21
Copy link

adame21 commented Mar 9, 2021

Hi,

What I want to be able to do is send my own HTTP/HTTPS agent - this is to be able to set keepAlive: true.

I tried looking through the library's code but couldn't find a way. (could barely understand what was going on - inexperienced with ts)

Does this option exist today?
Is it possible to add or make a workaround in my project to set it like this?

If its not possible I will have to "wrap" the gotenberg client myself which I really try to avoid.

Thanks :)
Update:
I just noticed you added "adjust" in your latest version.
It looks like it might be able to do what I need.
Can you let me know if this code does it ?

            const toPDF = pipe(
                gotenberg(getVariableValue("GOTENBERG_BASE_URL")),
                convert,
                html,
                // set({
                //     waitDelay: "1.5"
                // }),
                adjust({
                    httpsAgent: new https.Agent({
                        keepAlive: true,
                        maxSockets: 1
                    })
                }),
                to({
                    marginTop: margin.top,
                    marginBottom: margin.bot,
                    marginLeft: margin.left,
                    marginRight: margin.right,
                    landscape
                }),
                please
            )
@yumauri
Copy link
Owner

yumauri commented Mar 9, 2021

Hello!

You can do it :) Actually, there are few options (none is documented though...). But not with adjust — this function can be used to change internal request object, this is not actual HTTP request.

Function gotenberg actually accepts from one to three arguments:

  • URL to Gotenberg instance
  • HTTP Client
  • Config for HTTP Client

It tries to guess type of a second argument, and if it is not HTTP client — it is considered to be config for embeded client.
Reqular Node.js http.request and https.request are used in embeded client, so you should be able to add any available options here, for example:

gotenberg(
  getVariableValue("GOTENBERG_BASE_URL"),
  { agent: new http.Agent({ keepAlive: true }) }
),

As stated in the 1, you can create and pass completely your own HTTP client to gotenberg function.

HTTP Client (GotenbergClient) could be a plain object with fields post and optional get (get is used for ping requests, so if you don't use them, you can omit it), or it could be a function, which will be called with third config argument, and should return object with fields post and optional get, or it could be a class, which will be instantiated with third config argument, and should have methods post and optional get.

Then post method is called with three arguments:

  • url: string
  • data: FormData
  • headers?: { [header: string]: number | string | string[] | undefined }

and should return Promise<NodeJS.ReadableStream> (in fact you can return any response format you want from your client — this response will be returned from the whole pipe execution)

@yumauri
Copy link
Owner

yumauri commented Mar 9, 2021

Sidenote about point 1:
If you want to use same http.Agent for all requests, you should create is once, obviously. Best way is to define toPDF function once, like global one (don't create it each time you want to convert your documents). Or create http.Agent once, and use link to it in pipe execution.
If you will create toPDF function each time, and creates http.Agent each time — this will be useless, because each request will use separate Agent.

@adame21
Copy link
Author

adame21 commented Mar 9, 2021

Hi !
Thanks so much for such a fast and elaborate response.
I am testing both options and seeing what works best for my case.
Your sidenote about point 1 was very important to me as I do actually create toPdf every time, but its mainly because the margins arent always the same.
So if I wish to change one of the parameters passed to gotenberg func I have to re-create it ?
Regardless, I will use this advice, and close this issue by then end of the day with my results.
Thanks again !

Update:
Once again I replied too early.
I read again what you wrote, I will simply create a HTTPS agent and recycle it, while changing toPdf only in case of margin changes.
Will update again and close once im done .

Thanks !

@yumauri
Copy link
Owner

yumauri commented Mar 9, 2021

Sidenote about point 2:

Here are different examples of custom HTTP client, based on got library (I didn't try them though, but to show an idea it should be enough):

  1. Plain object:
const client = {
  post(url, body, headers) {
    return got.post(url, { body, headers })
  }
}
  1. Function
function client(config) {
  // you can use config here for some preparations
  return {
    post(url, body, headers) {
      return got.post(url, { body, headers })
    }
  }
}
  1. Class
class client {
  constructor(config) {
    // you can use config here for some preparations
  }

  post(url, body, headers) {
    return got.post(url, { body, headers })
  }
}

Then you can use this client in gotenberg function:

gotenberg(
  getVariableValue("GOTENBERG_BASE_URL"),
  client, // one of the clients from above
  config // any config for your client
),

@yumauri
Copy link
Owner

yumauri commented Mar 9, 2021

Your sidenote about point 1 was very important to me as I do actually create toPdf every time, but its mainly because the margins arent always the same.

pipe function is actually pure functional pipe function, it hasn't any library-specific functionality. I've added it to library just for convinience, but you can use any pipe implementation you want, for example, _.pipe or _.flow from lodash, or R.pipe from Ramda, or R.pipe from Rambda — in other words it just calls functions in order, from left to right, passing argument to the first one, and then passing return value from one function as argument to another function, to the last one.

So, please — is a function, which actually sends a request.

As this is technique from functional programming — you can partially apply pipe, like this:

const partialToPDF = pipe(
  gotenberg(
    getVariableValue("GOTENBERG_BASE_URL"),
    { agent: new http.Agent({ keepAlive: true }) }
  ),
  convert,
  html,
)

// ---8<---

function convertMyDocument(document) {
  const toPDF = pipe(
    partialToPDF,
    to({
      marginTop: margin.top,
      marginBottom: margin.bot,
      marginLeft: margin.left,
      marginRight: margin.right,
      landscape
    }),
    please
  )
  return toPDF(document)
}

So if I wish to change one of the parameters passed to gotenberg func I have to re-create it ?

If you pass to modifiers more than once — latest one should rewrite previous, so in my example above you can add margins to partialToPDF, and redefine them in convertMyDocument if needed.

@yumauri
Copy link
Owner

yumauri commented Mar 9, 2021

Note, that you can't change conversion type in partial pipe application, because convert and html (office/markdown/...) functions are adding path part to the url. So if you try to do smth like this:

pipe(
  gotenberg(...),
  convert,
  url,
  html,
  ...
)

It will use path gotenberg/convert/url/html, which is not a valid path for Gotenberg.

But I've got you covered, and made an exception for such case :) Following issue #14

But overriding margings, paper size, orientation and any headers should work fine.

@yumauri
Copy link
Owner

yumauri commented Mar 9, 2021

Sorry for amount of comments :)

You also can make smth like this:

// define this globally
const myGotenberg = gotenberg(
  getVariableValue("GOTENBERG_BASE_URL"),
  { agent: new http.Agent({ keepAlive: true }) }
)

// then use this function in pipe

const toPDF = pipe(
  myGotenberg,
  convert,
  html,
  to({
    marginTop: margin.top,
    marginBottom: margin.bot,
    marginLeft: margin.left,
    marginRight: margin.right,
    landscape
  }),
  please
)

@adame21
Copy link
Author

adame21 commented Mar 9, 2021

Hello,
My mind is blown by this amazing support.
I hope I can repay this kindness somehow.
I decided to simply create an https agent on the top of the module (as in - same agent every time)
I use two different functions for office and html so no problem there.
I still create toPdf every time, but I use the same agent.
It works muy bueno.
Again your support was amazing, thank you so much.
I'm happy for anyone with the same question stumbling to this issue.
:)

@adame21 adame21 closed this as completed Mar 9, 2021
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants