I have a tcl (expect) script to log into devices and transfer files. Unfortunately, the files are large, and during the transfer period the ssh connection ends (the files are still transferred though). So I basically have to login again before I can perform more actions on the device. Since the whole login process is long, I put it in a proc. The issue is that the proc logs into the device, but after the login, the script sends the commands to the terminal as, for some reason, the commands no longer reach the device. I cant figure out why the session I logged into in the proc does not carry over to the rest of the script.
proc login {} {
#login code - it works because I took it from the main script (which works).
# variables are all declared as global, no errors are thrown. Login is successful
}
login
send "show\r" ;# this command is not sent to the device,
#instead it prints to the terminal. When in the main script,
#these commands would not be printed to the terminal window.
Is there a command I am missing to maybe return the login session to the rest of the script? something similar to the interact command, but to the rest of the script.
This is a tricky one. The expect man page says this:
Expect takes a rather liberal view of scoping. In particular, variables read by commands specific
to the Expect program will be sought first from the local scope, and if not found, in the global
scope. For example, this obviates the need to place "global timeout" in every procedure you write
that uses expect. On the other hand, variables written are always in the local scope (unless a
"global" command has been issued). The most common problem this causes is when spawn is executed in
a procedure. Outside the procedure, spawn_id no longer exists, so the spawned process is no longer
accessible simply because of scoping. Add a global spawn_id to such a procedure.
So, add global spawn_id as the first line of the login proc
To make a procedure that evaluates code in its caller's scope, you need to use the uplevel command inside it. This lets you do what is essentially a macro very easily:
proc login {} {
uplevel {
# Put your code in here, which might look like this
spawn ssh user#host ...
expect Password:
send $thePassword\r
expect "bash$"
}
}
Then, when you use login it will work exactly like the commands you have inside the uplevel in the procedure, as if they'd been typed in place of the login call.
This isn't usually a particularly recommended approach, as it is very easy to make code that is inflexible and inclined to break unexpectedly, but in your case it is a very easy approach since you can easily guarantee to only call login at a sensible place in the overall program structure. (The uplevel command is more commonly used with scripts passed in with arguments — it's just like you're passing in a block — but that's not what you need.)
Related
I have used many discord API wrappers, but as an experienced python developer, unfortunately I somehow still do not understand how a command gets called!
#client.command()
async demo(ctx):
channel = ctx.channel
await channel.send(f'Demonstration')
Above a command has been created (function) and it is placed after its decorator #client.command()
To my understanding, the decorator is in a way, a "check" performed before running the function (demo) but I do not understand how the discord.py library seemingly "calls" the demo function.....?? Is there some form of short/long polling system in the local imported discord.py library which polls the discord API and receives a list of jobs/messages and checks these against the functions the user has created?
I would love to know how this works as I dont understand what "calls" the functions that the user makes, and this would allow me to make my own wrapper for another similar social media platform! Many thanks in advance.
I am trying to work out how functions created by the user are seemingly "called" by the discord.py library. I have worked with the discord.py wrapper and other API wrappers before.
(See source code attached at the bottom of the answer)
The #bot.command() decorator adds a command to the internal lists/mappings of commands stored in the Bot instance.
Whenever a message is received, this runs through Bot.process_commands. It can then look through every command stored to check if the message starts with one of them (prefix is checked beforehand). If it finds a match, then it can invoke it (the underlying callback is stored in the Command instance).
If you've ever overridden an on_message event and your commands stopped working, then this is why: that method is no longer being called, so it no longer tries to look through your commands to find a match.
This uses a dictionary to make it far more efficient - instead of having to iterate over every single command & alias available, it only has to check if the first letters of the message match anything at all.
The commands.Command() decorator used in Cogs works slightly different. This turns your function into a Command instance, and when adding a cog (using Bot.add_cog()) the library checks every attribute to see if any of them are Command instances.
References to source code
GroupMixin.command() (called when you use #client.command()): https://github.com/Rapptz/discord.py/blob/24bdb44d54686448a336ea6d72b1bf8600ef7220/discord/ext/commands/core.py#L1493
As you can see, it calls add_command() internally to add it to the list of commands.
Adding commands (GroupMixin.add_command()): https://github.com/Rapptz/discord.py/blob/24bdb44d54686448a336ea6d72b1bf8600ef7220/discord/ext/commands/core.py#L1315
Bot.process_commands(): https://github.com/Rapptz/discord.py/blob/master/discord/ext/commands/bot.py#L1360
You'll have to follow the chain - most of the processing actually happens in get_context which tries to create a Context instance out of the message: https://github.com/Rapptz/discord.py/blob/24bdb44d54686448a336ea6d72b1bf8600ef7220/discord/ext/commands/bot.py#L1231
commands.Command(): https://github.com/Rapptz/discord.py/blob/master/discord/ext/commands/core.py#L1745
I'm trying to deploy an app to production and getting a little confused by environment and application variables and what is happening at compile time vs runtime.
In my app, I have a genserver process that requires a token to operate. So I use config/releases.exs to set the token variable at runtime:
# config/releases.exs
import Config
config :my_app, :my_token, System.fetch_env!("MY_TOKEN")
Then I have a bit of code that looks a bit like this:
defmodule MyApp.SomeService do
use SomeBehaviour, token: Application.get_env(:my_app, :my_token),
other_config: :stuff
...
end
In production the genserver process (which does some http stuff) gives me 403 errors suggesting the token isn't there. So can I clarify, is the use keyword getting evaluated at compile time (in which case the application environment doest exist yet)?
If so, what is the correct way of getting runtime environment variables in to a service like this. Is it more correct to define the config in application.ex when starting the process? eg
children = [
{MyApp.SomeService, [
token: Application.get_env(:my_app, :my_token),
other_config: :stuff
]}
...
]
Supervisor.start_link(children, opts)
I may have answered my own questions here, but would be helpful to get someone who knows what they're doing confirm and point me in the right way. Thanks
elixir has two stages: compilation and runtime, both written in Elixir itself. To clearly understand what happens when one should figure out, that everything is macro and Elixir, during compilation stage, expands these macros until everything is expanded. That AST comes to runtime.
In your example, use SomeBehaviour, foo: :bar is implicitly calling SomeBehaviour.__using__/1 macro. To expand the AST, it requires the argument (keyword list) to be expanded as well. Hence, Application.get_env(:my_app, :my_token) call happens in compile time.
There are many possibilities to move it to runtime. If you are the owner of SomeBehaviour, make it accept the pair {:my_app, :my_token} and call Application.get_env/2 somewhere from inside it.
Or, as you suggested, pass it as a parameter to children; this code belongs to function body, meaning it won’t be attempted to expand during compilation stage, but would rather be passed as AST to the resulting BEAM to be executed in runtime.
I try to call windows function inside my custom assembly function
The pseudocode would be something like:
MYFUNC
PUSH EBP
PUSH WINDOWSFUNCTIONPARAMETER
CALL [IMPORTEDWINDOWSFUNCTION]
POP EBP
RET
So I know its safe to leave this like this if I call only one function inside,
because thie stack will be restored anyway.
The problem is- why can't i add esp, 0x04 after this? - The app crashes
Im not sure if i even need to do this but imo its safer to do it after function
calls, and somehow i cant get this working inside a function
I'm gratefull for any help :)
I am not sure what you mean by "after this". Basically:
On a x86 architecture, the stack grows downwards.
Depending on your calling convention, either the caller or the callee cleans up the stack.
You are calling a windows function, therefore i assume the called function cleans up the stack parameters. This leads me to the following conclusion:
If you execute "add esp, 0x04" after your API call, "pop ebp" will receive the return address instead of the previously saved ebp register. Therefore, the final "ret" will fail and not return to the caller of MYFUNC.
If you want to perform "add esp, 0x04" to remove the function parameter: thats not necessary because the windows API has removed it already.
EDIT:
If you have a simple example like the one above, I recommend to use a debugger like ollydbg, x64dbg, etc. They are free and show you the registers, stack, etc. while your app is running.
I'm trying to draw on a canvas that is in the top level of my Tcl/Tk script, but from inside a call by fileevent like this:
canvas .myCanvas {}
proc plot_Data { myC inp } { $myC create rectangle {} }
fileevent $inp readable [list plot_Data .myCanvas $inp ]
pack .myCanvas
I have found out that the script called by fileevent (plot_Data) lives in a different space.
The script for a file event is executed at global level (outside the context of any Tcl procedure) in the interpreter in which the fileevent command was invoked.
I cannot make the two meet. I have definitely narrowed it down to this: plot_Data just can't access .myCanvas . Question: How can the fileevent script plot on the canvas?
The goal of this is live plotting, by the way. $inp is a pipe to a C-program that reads data from a measurement device. It is imho rightly configured with fconfigure $inp -blocking 0 -buffering none.
Callback scripts (except for traces, which you aren't using) are always called from the context of the global namespace. They cannot see any stack frames above them. This is because they are called at times that aren't closely controlled; there's no telling what the actual stack would be, so it is forced into a known state.
However, canvases (and other widgets) have names in the global namespace as well. Your callbacks most certainly can access them, provided the widget has not been destroyed, and might indeed be working. You just happen to have given it an empty list of coordinates to create, which is not usually legal to use with a canvas item.
Since you are using non-blocking I/O, you need to be aware that gets may return the empty string when reading an incomplete line. Use fblocked to determine if a partial read happened; if it does, the data is in a buffer on the Tcl side waiting for the rest of the line to turn up, and it is usually best to just go to sleep and wait for the next fileevent to fire.
A problem that might bite you overall is if the C program is in fully buffered mode; this is true by default when writing output from C to a pipe. Setting the buffering on the Tcl side won't affect it; you need to use setvbuf on the C side, or insert regular fflush calls, or use Expect (which pretends to be an interactive destination, though at quite a lot of cost of complexity of interaction) or even unbuffer (if you can find a copy).
I have a C shell that usually calls Tcl routines using Tcl_Eval. Normally I was fine with just executing what the user typed and getting some status as a result. However, now I need to receive the actual stdio output from the command that user typed. Is there any way to get it using the Tcl C procedures?
As a side note: I need to figure out the list of current procedures available in the Tcl interpreter, both built in and user sourced. Basically, the output from info procs *.
I think you could go like this:
Create a pipe by calling pipe(2).
Then in your interp:
Close stdout by calling Tcl_Close() on it.
Turn the write-end file descriptor of your pipe into Tcl's stdout channel by calling Tcl_MakeChannel() right after closing stdout.
Or use just replace the stdout with a call to Tcl_SetStdChannel().
Process the data coming from the pipe.
As to your side note — I think you could just call Tcl_Eval() in your interpreter and process the returned list using the list-processing functions from the Tcl API.
Update (from one of my comments): after some more thought I think it might be possible to just create a custom Tcl channel which implementation would just save away the data written to it and then register an instance of such a channel as stdout. See Tcl_CreateChannel() and Tcl_RegisterChannel().