Python - Bots, Asyncio, Javascript, and Loops - javascript

Hello Everyone and thank you for your time. In the previous couple of days I have been undergoing a little project of mine to create a online chatbot for LINE. I understand the API but ran into a problem. I am trying to get my chabot to use online responses to user text. To accomplish this I am trying to use a websocket between python and JavaScript. The API I am using is in python hence the websocket must also be written in Python. I picked asyncio websockets. In short, I am trying to fetch a response from a user input on Line --> Send that response over a websocket to my javascript in a browser console --> The javascript will proceed with it's logic and send the response back to the server --> the Program will proceed with it's execution. My problem is that both the Websocket programming as well as my Line programming use a loop. The Line Code can be seen at
https://github.com/fadhiilrachman/line-py/blob/master/examples/groupbot.py
As you can see at the end of the code there is a while statement which traces the READ_MESSAGE Function over and over again for each message. You can ignore the NOTIFIED_LEAVE one. So basically my code while proceed with it's own logic and then do something like:
else:
#ExternalBot code
ExtText = text[6:]
I now wish to send this ExtText over my websocket to my javascript which will fetch a response from the browser and send it back. The javascript will do something like this:
exampleSocket = new WebSocket("ws://192.168.1.9:8765/")
exampleSocket.onmessage = function(e){
var server_message = e.data;
console.log(server_message);
(logic)
exampleSocket.send(response);
Now this is where the problem begins as I simply do not know how to proceed. The python asyncio Websockets requires a loop to run as seen below:
async def Send(websocket, path):
await websocket.send(ExtText)
await Receive(websocket, path)
async def Receive(websocket, path):
resposne = await websocket.recv()
if response is None:
await Recieve(websocket, path)
else:
print (Response)
start_server = websockets.serve(Send,'192.168.1.9','8765')
loop = asyncio.get_event_loop()
loop.run_untill_complete(start_server)
loop.run_forever()
(continue to do a line.send() the response back to the client on Line.)
This is the code that I currently have. Now the problem is, If I never close the loop the loop with something like loop.call_soon_threadsafe(loop.stop) it will keep running and in turn the message will never get sent back to the client(the program will not proceed with it's LINE logic). if I DO close the loop the server is "shutdown" in effect. If the server is shutdown and reopened for each message I have to send over the websocket, I now face the problem of getting my JavaScript to continually try to reconnect to the server every single message. I have tried this and have never succeeded in getting the Javascript to keep trying to establish a connection. I have tried to use Javascript websocket readyState attribute but that hasn't worked either. I am coming here simply because I Have no idea on how to proceed and what to do further. How do you people suggest I proceed, closing the loop or somehow leaving it open but continuing with my program's logic. If so how would you go about implementing it into my already looping code( the LINE while true statement)? I really do apologize for such a long question but I am completely stuck. Thank you for your time people who decide to read and help me, I really appreciate it.

After days of research I have solved the issue by separating the loops into two python scripts and communicating between them. If anyone here has a similar issue and wishes a more in depth explanation, feel free to ask me.

Related

Fastest redirects Javascript

My main function is I am creating a link-shortening app. When someone entered a long URL, it will give a short URL. If the user clicked on the short link it will search for the long URL on the DB and redirect it to the long URL.
Meantime I want to get the click count and clicked user's OS.
I am currently using current code :
app.get('/:shortUrl', async (req, res) => {
const shortUrl = await ShortUrl.findOne({short: req.params.shortUrl})
if (shortUrl == null) return res.sendStatus(404)
res.redirect(shortUrl.full)
})
findOne is finding the Long URL on the database using ShortID. I used mongoDB here
My questions are :
Are there multiple redirect methods in JS?
Is this method work if there is a high load?
Any other methods I can use to achieve the same result?
What other facts that matter on redirect time
What is 'No Redirection Tracking'?
This is a really long question, Thanks to those who invested their time in this.
Your code is ok, the only limitation is where you run it and mongodb.
I have created apps that are analytics tracker, handling billion rows per day.
I suggest you run your node code using AWS Beanstalk APP. It has low latency and scales on your needs.
And you need to put redis between your request and mongodb, you will call mongodb only if your data is not yet in redis. Mongodb has more read limitations than a straight redis instance.
Are there multiple redirect methods in JS?
First off, there are no redirect methods in Javascript. res.redirect() is a feature of the Express http framework that runs in nodejs. This is the only method built into Express, though all a redirect response consists of is a 3xx (often 302) http response status and setting the Location header to the redirect location. You can manually code that just as well as you can use res.redirect() in Express.
You can look at the res.redirect() code in Express here.
The main things it does are set the location header with this:
this.location(address)
And set the http status (which defaults to 302) with this:
this.statusCode = status;
Then, the rest of the code has to do with handling variable arguments, handling an older design for the API and sending a body in either plain text or html (neither of which is required).
Is this method work if there is a high load?
res.redirect() works just fine at a high load. The bottleneck in your code is probably this line of code:
const shortUrl = await ShortUrl.findOne({short: req.params.shortUrl})
And, how high a scale that goes to depends upon a whole bunch of things about your database, configuration, hardware, setup, etc... You should probably just test how many request/sec of this kind your current database can handle.
Any other methods I can use to achieve the same result?
Sure there are. But, you will have to use some data store to look up the shortUrl to find the long url and you will have to create a 302 response somehow. As said earlier, the scale you can achieve will depend entirely upon your database.
What other facts that matter on redirect time
This is pretty much covered above (hint, its all about the database).
What is 'No Redirection Tracking'?
You can read about it here on MDN.

WSS from JavaScript to plain Java

I am trying to create a websocket connection from JavaScript code to a Java server. I have managed to do this with a unsecure ws connection, but because the website that I want to use this code on is a secure https side, I have to use a secure websocket.
I have spend quite some time on research trying to get this to work, however I can't figure out how to get them connected. I have absolutely no experience with stuff like keystores or ciphers, but I don't need that security, I don't want to send any sensitive data.
Anyways, here is what I've tried:
SLLServerSocket server = (SSLServerSocket) SSLServerSocketFactory
.getDefault().createServerSocket(1234);
SSLSocket client = (SSLSocket) server.accept();
with corresponding JavaScript code:
var socket = new WebSocket("wss://localhost:1234")
socket.onopen = () => console.log("Connected");
socket.onmessage = m => console.log("Message received:", m);
Running this resulted in a Caused by: javax.net.ssl.SSLHandshakeException: No available authentication scheme which I managed to fix by adding
System.setProperty("jdk.tls.server.protocols", "TLSv1.2");
Now I am getting the exception javax.net.ssl.SSLHandshakeException: no cipher suites in common. I've done some research on that as well but whatever I find seems assume that a keystore or something is already there, which it is not for me. In fact I don't really know what encryption it should use, I did not find anything about that
To be fair, part of the problem may very well be that I don't know what to actually search for, but that is why I am asking. There are already articles about these exceptions I am showing, I know them, and they didn't help.

NodeJS Returning data to client browser

I think we need some help here. Thanks in advance.
I have been doing programming in .Net for desktop applications and have used Timer objects to wait for a task to complete before the task result are shown in a data grid. Recently, we switched over to NodeJs and find it pretty interesting. We could design a small application that executes some tasks using PowerShell scripts and return the data to the client browser. However, I would have to execute a Timer on the client browser (when someone clicks on a button) to see if the file, that Timer receives from the server, has "ENDOFDATA" or not. Once the Timer sees ENDOFDATA it triggers another function to populate DIV with the data that was received from the server.
Is this the right way to get the data from a server? We really don't want to block EventLoop. We run PowerShell scripts on NodeJS to collect users from Active Directory and then send the data back to the client browser. The PowerShell scripts are executed as a Job so EventLoop is not blocked.
Here is an example of the code at NodeJs:
In the below code can we insert something that won't block the EventLoop but still respond to the server once the task is completed? As you can see in the code below, we would like to send the ADUsers.CSV file to the client browser once GetUsers.PS1 has finished executing. Since GetUSers.PS1 takes about five minutes to complete the Event Loop is blocked and the Server can no longer accept any other requests.
app.post("/LoadDomUsers", (request, response) => {
//we check if the request is an AJAX one and if accepts JSON
if (request.xhr || request.accepts("json, html") === "json") {
var ThisAD = request.body.ThisAD
console.log(ThisAD);
ps.addCommand("./public/ps/GetUsers.PS1", [{
name: 'AllParaNow',
value: ScriptPara
}])
ps.addCommand(`$rc = gc ` + __dirname + "/public/TestData/AD/ADUsers.CSV");
ps.addCommand(`$rc`);
ps.invoke().then((output) => {
response.send({ message: output });
console.log(output);
});
}
});
Thank you.
The way you describe your problem isn't that clear. I had to read some of the comments in your initial question just to be sure I understood the issue. Honestly, you could just utilize various CSV NPM packages to read and write from your active directory with NodeJS.
I/O is non-blocking with NodeJS, so you're not actually blocking the EventLoop. You can handle multiple I/O requests, since NodeJS will just create threads for each one,
and continue execution on the main thread until the I/O operations complete and send back the data to its function reference, adding them as functions to the callstack and resuming program execution from those function's references. After you get the I/O data, you just send it back to the client through the response object. There should be no timers needed.
So is the issue once the powershell script runs, you have to wait for that initial script to complete before being able to handle pending requests? I'm still a bit unclear...

With Electron/Node.js, how do I implement simple sequential code asynchronously?

I am working on a project where my Electron App interacts with a physical device using serial commands, via serialport. The app sends a string to the device, the device executes the command (which can take ~30s) and then sends back a string to signify completion and results from that operation.
My goal is to automate a series of actions. For that, basically the following needs to be done asynchronously, so that the render thread doesn't get blocked:
Start a loop
Send a string to the device
Wait until a specific response comes back
Tell the render thread about the response, so it can update the UI
Afterwards, repeat with the next string.
Actually, multiple different commands need to be send in each loop cycle, and between each one the app has to wait for a specific string from the device.
This is kind of related to my last question, What's the correct way to run a function asynchronously in Electron?. From that, I know I should use web workers to run something asynchronously. However, my plan turned out to involve more problems than I anticipated, and I wanted to ask what would be a good way to implement this, having the whole plan in mind and not just a certain aspect of it.
I am especially not sure how to make the worker work with serialport. The serial device it needs to interact with is a child of the render process, so sending commands will probably be done over web worker messages. But I have no idea on how to make the worker wait for a specific response from the device.
(Since this question is of a more general nature, I am unsure whether I should provide some code snippets. If this is to general, I can try to write some pseudo code to make my problem more clear.)
I would go for a promise-based approach like this:
let promiseChain = Promise.resolve();
waitForEvent = function(){
return new Promise(resolve=>{
event.on("someEvent", (eventData => {
resolve(eventData)
}))
})
}
while(someLoopCondition) {
promiseChain = promiseChain
.then(sendToSerialPort(someString))
.then(waitForEvent)
.then(result=>{
updateUI(result)
})
}

Need some clarification on nodejs concepts

I am starting to learn more about how this "web world" works and that's why I am taking the free code camp course. I already took front-end development and I really enjoyed it. Now I am on the back end part.
The back end is much more foggy for me. There are many things that I don't get so I would hope that someone could help me out.
First of all I learned about the get method. so I did:
var http = require('http');
and then made a get request:
http.get(url, function callBack(response){
response.setEncoding("utf8");
response.on("data", function(data){
console.log(data);
});
});
Question 1)
So apparently this code "gets" a response from a certain URL. but What response? I didn't even ask for anything in particular.
Moving on...
The second exercise asks us to listen to a TCP connection and create a server and then write the date and time of that connection. So here's the answer:
var server = net.createServer(function listener (socket){
socket.end(date);
});
server.listen(port);
Question 2)
Okay so I created a TCP server with net.createServer() and when the connection was successful I outputted the date. But where? What did actually happen when I put date inside of socket.end()?
Last but not least...
in the last exercise I was told to create an HTTP server (what?) to server a text file for every time it receives requests, and here's what I did:
var server = http.createServer(function callback(request, response){
var read = fs.createReadStream(location);
read.pipe(response);
});
server.listen(port);
Question 3)
a) Why did I have to create an HTTP server instead of a regular TCP? what's the difference?
b)what does createReadStream do?
c) What does pipe() do?
If someone could help me, trying to make the explanation easier would help me a lot since I am, as you can see, pretty dumb on this subject.
Thank you a lot!
This is a little broad for Stackoverflow which favors focused questions that address specific problems. But I feel your pain, so…
Questions 1:
Http.get is roughly equivalent to requesting a webpage. The url in the function is the page you are requesting. The response will include several things like the HTTP response code, but also (most importantly) the content of the page, which is what you are probably after. On the backend this is normally used for hitting APIs that get data rather than actual web pages, but the transport mechanism is the same.
Question 2:
When you open a socket, you are waiting for someone else to request a connection. (The way you do when you use http.get(). When you output data you are sending them a response like the one you received in question 1.
Question 3:
HTTP is a higher level protocol than TCP. This basically means it is more specific and TCP is more general (pedants will take issue with that statement, but it's an easy way to understand it). HTTP defines the things like GET and POST that you use when you download a webpage. Lower down in the protocol stack HTTP uses TCP. You could just use TCP, but you would have to do a lot more work to interpret the requests that come in. The HTTP library does that work for you. Other protocols like FTP also use TCP, but they are different protocol than HTTP.
For this answer, you need to understand two things. An IP address is the numeric value of a website, it's the address to the server pointing to the site. A domain name is a conversion from IP to a NAMED system which allows humans an easier way to see the names of websites, so instead of typing numbers for websites, like 192.168.1.1, we can now just type names (www.hotdog.com). That's what your get request is doing, it's requesting the site.
socket.end is a method you're calling. socket.end "Half-closes the socket. i.e., it sends a FIN packet. It is possible the server will still send some data" from the nodejs.org docs, so basically it half closes your socket at the parameter you're sending in, which is todays current date.
HTTP is hyper text transfer protocol, TCP (transmissioncontrol protocol) is a link between two computers
3a HTTP is for browsers, so that's why you did it, for a web page you were hosting locally or something.
3b createreadstream() Returns a new ReadStream object. (See Readable Stream).
Be aware that, unlike the default value set for highWaterMark on a readable stream (16 kb), the stream returned by this method has a default value of 64 kb for the same parameter.
3c pipe:
The 'pipe' event is emitted when the stream.pipe() method is called on a readable stream, adding this writable to its set of destinations.

Categories

Resources