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

Rework framework adapters, and add new ones #61

Merged
merged 21 commits into from
Nov 29, 2021

Conversation

kraftwerk28
Copy link
Contributor

No description provided.

Copy link
Member

@KnorpelSenf KnorpelSenf left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The http and https adapters correspond to the native Node modules. They are not intended to behave differently per platform.

Thanks for adding support for the std/http server of Deno! Rather than making the existing http identifier ambiguous, we should add a new name for the adapter. Pick any you like.

Your PR starts dividing the supported platforms into the platform-specific code. This used not to be the case. I don't have strong opinions on the matter, but here are pros and cons of platform-specific code.

Pro:

  • no superfluous entries in autocomplete

Con:

  • missing Node adapters in API reference (edit: they don't show up there)
  • increases dependency on platform.{deno,node}.ts

@KnorpelSenf
Copy link
Member

Now that I think about it, it does indeed make a lot of sense to keep runtime-specific adapters in runtime-specific files.

Feel free to restructure platform.{deno,node}.ts and convenience/webhook.ts as you desire. It may be the case that some code needs to be duplicated in order to avoid cyclic dependencies between the two files.

It would still be preferable if there were no name clashes, i.e. that no framework adapter appears in both environments.

@KnorpelSenf
Copy link
Member

@kraftwerk28 awaiting your review.

const reqUrl = new URL(req.url);
return {
update: (req.method !== "POST" || reqUrl.pathname !== secretPath)
? Promise.resolve(undefined)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why resolving undefined? I'd expect a rejection here.

package.json Outdated Show resolved Hide resolved
src/convenience/frameworks.node.ts Outdated Show resolved Hide resolved
src/convenience/frameworks.node.ts Outdated Show resolved Hide resolved
src/convenience/frameworks.node.ts Outdated Show resolved Hide resolved
tsconfig.json Outdated Show resolved Hide resolved
timeoutMilliseconds = 10_000,
) {
const server = frameworkAdapters[framework] ?? standard;
adapter?: A,
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I missed this. This is a breaking change so we either have to wait with merging until 2.0 (some time later next year maybe?), or it has to be reverted.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Alternatively, we could introduce a union type. This would still permit string identifiers (non-breaking) but optionally allow people to pass their own adapter. May make it hard to find good types, not sure.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sure, this should be in the next major. Thought I feel that giving a choice among predefined frameworks has less flexibility than allowing to put either a custom one or import from grammY's code. I'll add a temporary union

Copy link
Member

@KnorpelSenf KnorpelSenf Nov 15, 2021

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't see why users would have to access the predefined objects. How about not exposing them, and simply allowing string identifiers as well as custom objects? One could pass a string to use a predefined one, or an object to define a custom one.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is there a reason for exposing them?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

image
This way it's ideal

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That's also what I have in mind. Plus, letting the adapters become implementation details that aren't exported.

@kraftwerk28 kraftwerk28 force-pushed the fix-http-adapter branch 2 times, most recently from f30722f to 680358e Compare November 19, 2021 13:18
@KnorpelSenf
Copy link
Member

Why the force-push? Did anything else change?

@kraftwerk28
Copy link
Contributor Author

I did a pull-rebase from main branch

@kraftwerk28
Copy link
Contributor Author

kraftwerk28 commented Nov 19, 2021

Is it OK to disable no-explicit-any lint rule for frameworks.*.ts?

@KnorpelSenf
Copy link
Member

I see. Now I'll need to go through all old commits again. Merge commits are usually much easier to review. Now that we're squash-merging PRs, so having a few merges on the feature branches isn't problematic.

@KnorpelSenf
Copy link
Member

Is it OK to disable no-explicit-any lint rule for frameworks.*.ts?

Yes.

Copy link
Member

@KnorpelSenf KnorpelSenf left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

IIRC we agreed on proceeding like this.

  1. Do not support path matching for now, introduce this with a breaking change in the next major version which can perform more substantial refactoring.
  2. Do not expose all config objects. Instead, let them be identified via strings. It is still allowed to pass your own config object, which effectively allows you to do path matching manually.
  3. The current organisation of files (separating Deno/Node) can stay that way, as long as 2 is applied.

Make sure the identifier of the adapters do not change. This is currently the case for at least awsLambda.

req.method !== "POST" ||
!safeStringCompare(secretPath, req.url ?? "")
) {
reject();
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please reject with an error that has a helpful error message

const raw = Buffer.concat(chunks).toString("utf-8");
resolve(JSON.parse(raw));
})
.once("error", (e) => reject(e));
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit:

Suggested change
.once("error", (e) => reject(e));
.once("error", reject);

Comment on lines 108 to 119
try {
await timeoutIfNecessary(
bot.handleUpdate(await update, webhookReplyEnvelope),
typeof onTimeout === "function"
? () => onTimeout(...args)
: onTimeout,
timeoutMilliseconds,
);
if (end !== undefined && !usedWebhookReply) end();
} catch {
// Adapter rejected processing an update
}
Copy link
Member

@KnorpelSenf KnorpelSenf Nov 21, 2021

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Also, we should not suppress errors, but throw them instead.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Does it mean an error occured if the adapter just rejected the request from Telegram (e.g. requrst.url !== secretPath)? Or we can create an class UpdateRejected extends Error and throw iif !(error instanceof UpdateRejected).

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We are not going to support secret path matching in this iteration. If an adapter throws, something is wrong.

If we later implement adapters that choose not to process some requests, they must integrate with their respective web frameworks, and e.g. call next().

@KnorpelSenf KnorpelSenf added the enhancement New feature or request label Nov 22, 2021
Copy link
Member

@KnorpelSenf KnorpelSenf left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM now.

As stated in the conversation above, we need to change the call signature of webhookCallback in order to support more complex options objects in a usable and convenient way. This is a breaking change that will be introduced in the next major release.

Until then, users must route their updates manually, and perform necessary path matching themselves if they decide to go for a low-level framework that does not support this out of the box.

@KnorpelSenf KnorpelSenf changed the title Add http adapters for Deno & Node Rework framework adapters, and add new ones Nov 29, 2021
@KnorpelSenf KnorpelSenf merged commit 14895d4 into grammyjs:main Nov 29, 2021
@KnorpelSenf
Copy link
Member

Thank you for this contribution, and my apologies that it took so long to get this through.

@all-contributors add @kraftwerk28 for code, ideas, and review!

@allcontributors
Copy link
Contributor

@KnorpelSenf

I've put up a pull request to add @kraftwerk28! 🎉

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
enhancement New feature or request
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

3 participants