How expensive is each WebDev route

first off, i promise this is distinct from my other questions (except for the py3 one)

how many web dev routes can a gateway easily run?

in particular, if someone were to programmatically generate...as many web dev routes as there are ignition system functions

would this break anything?

Find out and report back :slight_smile:

2 Likes

i might have to try this

if it works, i might well have a py3 scripting integration approach :slight_smile:

Is there an easy list of which system functions are idempotent?

There is not.

1 Like

You'll get a (lazy loaded), not completely insignificant though not terrible, hit to memory usage for each route loaded. You may not need lots of routes, though... if you're just trying to do something like webdev/scriptingProject/system/abc/xyz, you can use the remainingPath parameter to mount a "root" handler that steps through the lower indirection. No need to seed the system with a bunch of semi-hardcoded things.

2 Likes

silly paul, the more i get nerdsniped on this the less i work on [REDACTED PROJECT A] and 'py3 scripting support for ignition based on a wrapper lib and eval'

Do be surprised by the lack of uptake with that in it.

Yeah, in practice I probably wouldn't use eval, but instead would be using ast.compile and walking the globals dict -- if you've got a better way to avoid 'writing a web dev route for every individual system function' i'm all ears

(This is probably a matter for a separate thread, but the short version of the approach is 'wrapper around system functions by having the function calls get routed through a webdev handler that serializes out the response exceptions and outputs)

Uh, not any better. Sheesh. Paul gave you the answer over in the webdev topic: use remaining path, split on '/', use globals().get() on the first name, and then getattr() for subsequent names. Decode the payload into a list of argments and/or dictionary of keyword arguments. Call function. Encode response.

No need for eval or compile or any other hackable remote code injection.

:man_shrugging:

2 Likes

Does globals.get resolve import paths too? that's what I was worried about on the ast.compile side. (I would have been dropping all non-function name pieces of the AST after compiling).

No, it resolves what is reachable in the global module of the calling function. system will be there, along with all of the project library scripts of that project. Use dir() in a WebDev doGet() for more information. (You may want to constrain that first name lookup.)

Really, don't eval() or compile. Those are terrible for performance, dangerous, and just not necessary.

2 Likes

...sorry, just realized I mixed up compile and ast.parse, that would explain some of the concern

Rephrasing some of Phil's point:

Everywhere you run a script inside Ignition, we're automatically injecting a special object in under the keyword system. [1] That object, naturally, contains all the sub-namespaced functions (alarm, dataset, perspective [2], etc) - and those sub namespaces have all the inner functions, as standard Python callable objects.

That is, the one hack we're doing is automatically injecting system into the local scope. We are not attempting to do something like "find every usage of system.x.y in the string and hot-replace it with a dynamic hook to Java code" or something else insane. If you have a reference to system, it's a Python object like any other - same as the objects below it in the namespace. You can even do highly questionable things like:

db = system.db
exportCSV = system.dataset.exportCSV

And so on. So any of the standard Python metaprogramming stuff like getattr will "just work"; the below two lines are functionally equivalent:

db = system.db
db = getattr(system, "db")

  1. also all the project library scripts, but leaving that questionable past decision aside ↩︎

  2. in appropriate scope ↩︎

3 Likes

Ahhhhh, I hadn't realized that -- that does make this significantly easier