Как настроить сервер Python на стороне клиента javascript
Итак, уже установлена программа Python, которая запускается на консоли, на которой я должен основываться. Я буду создавать интерфейс веб-интерфейса для приложения, используя Javascript.
Как я:
а. Перейдите к обработке ввода/вывода этой программы Python, не касаясь исходного кода.
б. Переходите к отправке консольных вводов в программу Python с помощью вызовов Javascript. Я просмотрел необработанные HTTP-запросы/AJAX, но я не уверен, как именно я хотел бы отправить это как вход в программу Python.
Ответы
Ответ 1
а. Для обработки ввода/вывода программы: Pexpect. Он довольно прост в использовании, и чтение некоторых из распространенных с ним примеров должно научить вас достаточно, чтобы ослабить основы.
б. Интерфейс Javascript:
Ну, я использую gevent и встроенный сервер WSGI. (посмотрите, что сервер WSGI (еще) есть), Я должен отметить, что эта программа будет поддерживать состояние, поэтому вы можете управлять открытыми сеансами, возвращая идентификатор сеанса на ваш javascript-клиент и сохраняя свой сеанс pexpect в глобальной переменной или в каком-либо другом контейнере, чтобы вы могли завершить ввод и вывод программы через несколько независимых запросов AJAX. Однако я оставляю это за вас, поскольку это не так просто.
Весь мой пример будет делать запрос POST в некоторых после нажатия на что-то по вашему выбору. (на самом деле это не будет работать, потому что некоторые из переменных не заданы.).
Вот интересующие части:
<!-- JavaScript -->
<script src="jquery.js"></script>
<script type="text/javascript">
function toPython(usrdata){
$.ajax({
url: "http://yoursite.com:8080",
type: "POST",
data: { information : "You have a very nice website, sir." , userdata : usrdata },
dataType: "json",
success: function(data) {
<!-- do something here -->
$('#somediv').html(data);
}});
$("#someButton").bind('click', toPython(something));
</script>
Затем сервер:
# Python and Gevent
from gevent.pywsgi import WSGIServer
from gevent import monkey
monkey.patch_all() # makes many blocking calls asynchronous
def application(environ, start_response):
if environ["REQUEST_METHOD"]!="POST": # your JS uses post, so if it isn't post, it isn't you
start_response("403 Forbidden", [("Content-Type", "text/html; charset=utf-8")])
return "403 Forbidden"
start_response("200 OK", [("Content-Type", "text/html; charset=utf-8")])
r = environ["wsgi.input"].read() # get the post data
return r
address = "youraddresshere", 8080
server = WSGIServer(address, application)
server.backlog = 256
server.serve_forever()
Если ваша программа объектно-ориентированная, было бы довольно легко интегрировать ее. РЕДАКТИРОВАТЬ: Не нужно ориентироваться на объекты. и теперь я включил некоторый код Pexpect
global d
d = someClass()
def application(environ, start_response):
# get the instruction
password = somethingfromwsgi # read the tutorials on WSGI to get the post stuff
# figure out WHAT to do
global d
success = d.doSomething()
# or success = funccall()
prog = pexpect.spawn('python someprogram.py')
prog.expect("Password: ")
prog.sendline(password)
i = prog.expect(["OK","not OK", "error"])
if i==0:
start_response("200 OK", [("Content-Type", "text/html; charset=utf-8")])
return "Success"
elif i==1:
start_response("500 Internal Server Error", [("Content-Type", "text/html; charset=utf-8")])
return "Failure"
elif i==2:
start_response("500 Internal Server Error", [("Content-Type", "text/html; charset=utf-8")])
return "Error"
Другим вариантом, который я предлагаю, является Nginx + uWSGI. Если вы предпочтете это, я также могу привести некоторые примеры этого. Это дает вам возможность включить веб-сервер в настройку.
Ответ 2
Чтобы прозрачно передавать ваши данные из javascript во внешнюю программу Python, вы можете использовать протокол WebSocket для подключения своего сервера и javascript и использовать stdin/stdout для связи с внешней программой с сервера.
Вот пример программы Python client.py
:
#!/usr/bin/env python
"""Convert stdin to upper case."""
for line in iter(raw_input, 'quit'):
print line.upper()
Я создал сервер, используя код из приветственный пример веб-раскладки и SO ответьте как создать новый процесс для каждого входящего соединения и перенаправить все входные данные в процесс "stdin" :
#!/usr/bin/python
"""WebSocket CLI interface."""
import sys
from twisted.application import strports # pip install twisted
from twisted.application import service
from twisted.internet import protocol
from twisted.python import log
from twisted.web.server import Site
from twisted.web.static import File
from txws import WebSocketFactory # pip install txws
class Protocol(protocol.Protocol):
def connectionMade(self):
from twisted.internet import reactor
log.msg("launch a new process on each new connection")
self.pp = ProcessProtocol()
self.pp.factory = self
reactor.spawnProcess(self.pp, sys.executable,
[sys.executable, '-u', 'client.py'])
def dataReceived(self, data):
log.msg("redirect received data to process' stdin: %r" % data)
self.pp.transport.write(data)
def connectionLost(self, reason):
self.pp.transport.loseConnection()
def _send(self, data):
self.transport.write(data) # send back
class ProcessProtocol(protocol.ProcessProtocol):
def connectionMade(self):
log.msg("connectionMade")
def outReceived(self, data):
log.msg("send stdout back %r" % data)
self._sendback(data)
def errReceived(self, data):
log.msg("send stderr back %r" % data)
self._sendback(data)
def processExited(self, reason):
log.msg("processExited")
def processEnded(self, reason):
log.msg("processEnded")
def _sendback(self, data):
self.factory._send(data)
application = service.Application("ws-cli")
_echofactory = protocol.Factory()
_echofactory.protocol = Protocol
strports.service("tcp:8076:interface=127.0.0.1",
WebSocketFactory(_echofactory)).setServiceParent(application)
resource = File('.') # serve current directory INCLUDING *.py files
strports.service("tcp:8080:interface=127.0.0.1",
Site(resource)).setServiceParent(application)
Часть веб-клиента, sendkeys.html
:
<!doctype html>
<title>Send keys using websocket and echo the response</title>
<script src="http://ajax.googleapis.com/ajax/libs/jquery/1.7.0/jquery.min.js">
</script>
<script src="sendkeys.js"></script>
<input type=text id=entry value="type something">
<div id=output>Here you should see the typed text in UPPER case</div>
и sendkeys.js
:
// send keys to websocket and echo the response
$(document).ready(function() {
// create websocket
if (! ("WebSocket" in window)) WebSocket = MozWebSocket; // firefox
var socket = new WebSocket("ws://localhost:8076");
// open the socket
socket.onopen = function(event) {
socket.send('connected\n');
// show server response
socket.onmessage = function(e) {
$("#output").text(e.data);
}
// for each typed key send #entry text to server
$("#entry").keyup(function (e) {
socket.send($("#entry").attr("value")+"\n");
});
}
});
Чтобы попробовать:
- загрузить этот текст
-
установить twisted
, txws
:
$ pip install twisted txws
-
пробег:
$ twistd -ny wscli.py
-
посетите http://localhost:8080/
-
нажмите sendkeys.html
и введите что-то
Ответ 3
Вероятно, вы хотите Flask вместе с json module.
Django - еще один вариант, но, вероятно, слишком высокоуровневый для ваших нужд.
Ответ 4
Это зависит от того, какое приложение вы обертываете, и от того, как ваши параметры графического интерфейса преобразуются в команды приложения. Но у вас здесь две цели:
-
Написание обертки, позволяющей вам читать выходные данные вашей программы и предоставлять ее.
-
Создание веб-сервера для получения событий GUI и преобразования их в команды для перехода к вашей "обертке"
Я сделал что-то вроде того, что вам нужно сделать.
-
По существу вам нужно включить потоки сокетов в скрытые команды. Инструмент defacto для этого expect, и любой из них обертки (я использовал pexpect, оболочка Python, и имел хороший опыт работы с ней).
-
Эта часть может быть не простой. Проблема в том, что ваша базовая программа постоянно работает, и поэтому ваш веб-сервер должен быть в состоянии знать о программе через запросы. Другой вариант заключается в том, что ваш веб-сервер просто повторно присоединяется к процессу и выдает его команды и отправляет ответ, когда он встречается в потоке stdout, но вы можете получить длительное время ответа в зависимости от того, насколько быстро программа есть. Также существует несоответствие, что запросы AJAX являются асинхронными, а ваша базовая программа является синхронной. Так что да, это может стать довольно сложным. Это действительно зависит от вашей программы. Если бы вы могли добавить некоторые сведения о том, что такое программа и графический интерфейс, это поможет.