I'm unable to use 'applicationRunner' because it doesn't support auto-reconnect (GitHub Issues: #295 #389) for websockets. I've reverted to the deprecated approach that uses twisted 'ReconnectingClientFactory'. My issue is that this approach doesn't seem to allow me to add 'ssl.optionsForClientTLS' for strict verification of server hostname and certificate. Is there any way to accomplish this?
Really appreciate any feedback!
class MyClientFactory(websocket.WampWebSocketClientFactory, ReconnectingClientFactory):
maxDelay = config.maxretry
def clientConnectionFailed(self, connector, reason):
logging.debug("Connection Failed: %s", reason)
ReconnectingClientFactory.clientConnectionFailed(self, connector, reason)
def clientConnectionLost(self, connector, reason):
logging.debug("Connection Lost: %s", reason)
ReconnectingClientFactory.clientConnectionLost(self, connector, reason)
def start():
log.startLogging(sys.stdout)
component_config = types.ComponentConfig()
session_factory = wamp.ApplicationSessionFactory(config=component_config)
session_factory.session = MyFrontendComponent
transport_factory = MyClientFactory(session_factory, 'wss://services:8443/ws', debug=True)
transport_factory.debug = True
transport_factory.debugCodePaths = True
websocket.connectWS(transport_factory)
Thread(target=reactor.run, args=(False,)).start()
Nevermind, figured it out... hopefully this helps anyone else facing the same problem. Turns out 'connectWS' accepts a 'contextFactory' with 'optionsForClientTLS'. Now we have a auto-reconnecting WebSocket with strict certificate validation:
class MyClientFactory(websocket.WampWebSocketClientFactory, ReconnectingClientFactory):
maxDelay = 30
def clientConnectionFailed(self, connector, reason):
logging.debug("Connection Failed: %s", reason)
self.retry(connector)
def clientConnectionLost(self, connector, reason):
logging.debug("Connection Lost: %s", reason)
self.retry(connector)
def start():
log.startLogging(sys.stdout)
component_config = types.ComponentConfig()
session_factory = wamp.ApplicationSessionFactory(config=component_config)
session_factory.session = MyFrontendComponent
transport_factory = MyClientFactory(session_factory, 'wss://services:8443/ws', debug=True)
transport_factory.debug = True
transport_factory.debugCodePaths = True
context_factory = None
if transport_factory.isSecure:
certData = getModule(__name__).filePath.sibling('server_cert.pem').getContent()
authority = ssl.Certificate.loadPEM(certData)
context_factory = ssl.optionsForClientTLS(u'services', authority)
websocket.connectWS(transport_factory, context_factory)
Thread(target=reactor.run, args=(False,)).start()
Related
I created a server in python using asyncio.start_server but what I want is to enable TLS for this server after its creation. I know it's possible to enable TLS using the tls parameter when creating the server but I want to do it later in the code.
I saw How do I enable TLS on an already connected Python asyncio stream?, it doesn't help me understand what to do.
Thank you for your kind answer and your time reading this.
The code for the server :
# ..init some parameters for the server
async def start_tls_connection(client_reader: asyncio.StreamReader, client_writer: asyncio.StreamWriter):
global ID
global msgList
global onlineList
global socket_server
data = await PStream.read_from_stream(streamObject=client_reader, debugMessage='Got message from client :')
if data == None:
return -1 # Handshake failure
# before proceeding we must upgrade the socket of the server to one that enables tls :
context = get_context()
logging.debug('socket before = ' + str(socket_server.sockets[0]._sock))
logging.debug(str(context))
socket_server.sockets[0]._sock = context.wrap_socket(socket_server.sockets[0]._sock)
logging.debug('socket after = ' + str(ssl_sock))
# upgrade socket here
data = await PStream.write_from_stream(streamObject=client_writer,
msg='<proceed xmlns="urn:ietf:params:xml:ns:xmpp-tls"/>',
debugMessage='Answer sent from server :')
if data == '':
return -1 # Handshake failure
# waiting for client to send a new stream header
data = await PStream.read_from_stream(streamObject=client_reader, debugMessage='Got message from client :')
if data == None:
return -1 # Handshake failure
# ... others methods for handshake
async def on_connect_client(client_reader: asyncio.StreamReader, client_writer: asyncio.StreamWriter):
logging.debug("START OF HANDSHAKE\nFIRST STEP: STREAM SESSION")
res = await stream_init(client_reader, client_writer)
if res == -1:
return res
logging.debug("START OF TLS HANDSHAKE")
res = await start_tls_connection(client_reader, client_writer)
if res == -1:
return res
logging.debug("START OF AUTHENTIFICATION")
res = await handshake_auth(client_reader, client_writer)
if res == -1:
return res
logging.debug("START OF ROOSTER PRESENCE")
res = await handshake_rooster_presence(client_reader, client_writer)
if res == -1:
return res
logging.debug("Waiting for request...")
while True:
data = await PStream.read_from_stream(streamObject=client_reader, debugMessage='Got message from client :')
if data == None:
break
async def server_start():
global socket_server
socket_server = await asyncio.start_server(on_connect_client, IP, PORT) # tls=ssl_context not here yet
logging.debug("Server just started")
async with socket_server:
await asyncio.gather(socket_server.serve_forever())
if __name__ == '__main__':
try:
asyncio.run(server_start())
except Exception as e:
print("Exception: ", str(e))
The line where
socket_server.sockets[0]._sock = context.wrap_socket(socket_server.sockets[0]._sock)
is written is where I have a problem, I don't know how to enable TLS on an already existing asyncio.start_server object.
The get_context() methods works well so don't worry about it btw.
Consumer.py:
#!/usr/bin/env python
import pika, sys, os
def main():
connection = pika.BlockingConnection(pika.ConnectionParameters(host='localhost'))
channel = connection.channel()
channel.exchange_declare(exchange='headers_logs', exchange_type='headers')
channel.queue_declare(queue='', exclusive=True)
queue_name = "HeadersQueue1"
channel.queue_bind(exchange='headers_logs', queue=queue_name)
def callback(ch, method, properties, body):
print(" [x] %r" % body.decode())
print(' [*] Waiting for logs. To exit press CTRL+C')
channel.basic_consume(
queue=queue_name, on_message_callback=callback, auto_ack=True)
channel.start_consuming()
if name == 'main':
try:
main()
except KeyboardInterrupt:
print('Interrupted')
try:
sys.exit(0)
except SystemExit:
os._exit(0)
Publish.py:
#!/usr/bin/env python
import pika
import sys
connection = pika.BlockingConnection(pika.ConnectionParameters(host='localhost'))
channel = connection.channel()
channel.exchange_declare(exchange='headers_logs',exchange_type='headers')
message = ' '.join(sys.argv[1:]) or "Hello World!"
channel.basic_publish(exchange='headers_logs',headers={"name":"ram"},body=message)
print(" [x] Sent %r" % message)
connection.close()
Here I have written consumer and publish program like above. Can anyone please guide that how to write Simple headersExchange program in rabbitMq using python
To use a headers exchange, you need to declare the exchange type as headers, not fanout as in your question's text.
exchangeName = 'headers_logs'
channel.exchange_declare(exchangeName, exchange_type='headers', durable=True)
Then create the queue and bind it to the exchange using the headers. Note that 'x-match' here can be set to match any or all headers. The routing key is set to empty string because it will not be used for routing messages.
qName = 'queue_logs'
channel.queue_declare(queue=qNameI, durable=True)
channel.queue_bind(qName, exchangeName, routing_key='', arguments={'x-match': 'any', 'key1': 'one', 'key2': 'two'})
Now we can publish a message to the exchange with a set of headers:
channel.basic_publish(
exchange=exchangeName,
routing_key='',
body='test message body',
properties=pika.BasicProperties(
delivery_mode = 2, # make message persistent
headers = {'key1':'one', 'key2': 'three'}
)
)
I have only matched 'key1' in this message to demonstrate that 'x-match' has been set to 'any'.
server
I have tried almost everything to receive text from python
I don't know where the problem comes from from the client or from the server
try:
llamadacod = self.request.recv(1024)
llamada = self.decode(llamadacod)
print(f"{color.A}{llamada}")
time.sleep(0.1)
if llamada == "conectado":
msg = "Hello"
msgcod = self.encode(msg)
print(f"{color.G}{msg}")
self.request.send(msgcod)
client
val thread = Thread(Runnable {
try{
val client = Socket("localHost",25565)
client.setReceiveBufferSize(1024)
client.outputStream.write("conectado".toByteArray())
val text = InputStreamReader(client.getInputStream())
recibir = text.toString()
client.outputStream.write("Client_desconect".toByteArray())
client.close()
I already solved it, the solution was very simple, you just had to ensure that both the server and the client would occupy the same way of communicating
client :
val input = DataInputStream(client.getInputStream())
id = input.readUTF()
server:
self.request.send(len(msg).to_bytes(2, byteorder='big'))
self.request.send(msg)
It is well understood that forking a process for running Python, as CGI does, is slower than embedding Python, as WSGI does. I would like to implement an XML-RPC interface using the SimpleXMLRPCServer included in the standard Python library and I already have an implementation that works via CGI. I believe there should be a faster way. I'd like to try WSGI but first I need a request handler for WSGI and there does not appear to be one in SimpleXMLRPCServer already. Am I all wet or is there no equivalent of this in the standard library under Python 2.6, 2.7, 3.x?
Here is my initial implementation of a WSGI replacement for CGIXMLRPCRequestHandler:
from xmlrpclib import SimpleXMLRPCDispatcher
class WSGIXMLRPCRequestHandler(SimpleXMLRPCDispatcher):
"""Simple handler for XML-RPC data passed through WSGI."""
def __init__(self, allow_none = False, encoding = None):
SimpleXMLRPCDispatcher.__init__(self, allow_none, encoding)
def __call__(self, environ, start_response):
"""Parse and handle a single XML-RPC request"""
result = []
method = environ['REQUEST_METHOD']
headers = [('Content-type', 'text/html')]
if method != 'POST':
# Default implementation indicates an error because XML-RPC uses the POST method.
code = 400
message, explain = BaseHTTPServer.BaseHTTPRequestHandler.responses[code]
status = '%d %s' % (code, message)
if method == 'HEAD':
response = ''
else:
response = BaseHTTPServer.DEFAULT_ERROR_MESSAGE % {'code' : code, 'message' : message, 'explain' : explain}
else:
# Dispatch XML-RPC to implementation
status = '200 OK'
request = environ['wsgi.input'].read(int(environ['CONTENT_LENGTH']))
response = self._marshaled_dispatch(request)
length = len(response)
if length > 0:
result = [response]
headers.append(('Content-length', str(length)))
start_response(status, headers)
return result
Take a look at this Hope it'll help.
I have developed numerous iOS apps over the years so know Objective C reasonably well.
I'd like to build my first web service to offload some of the most processor intensive functions.
I'm leaning towards using my Mac as the server, which comes with Apache. I have configured this and it appears to be working as it should (I can type the Mac's IP address and receive a confirmation).
Now I'm trying to decide on how to build the server-side web service, which is totally new to me. I'd like to leverage my Objective C knowledge if possible. I think I'm looking for an Objective C-compatible web service engine and some examples how to connect it to browsers and mobile interfaces. I was leaning towards using Amazon's SimpleDB as the database.
BTW: I see Apple have Lion Server, but I cannot work out if this is an option.
Any thoughts/recommendations are appreciated.?
There are examples of simple web servers out there written in ObjC such as this and this.
That said, there are probably "better" ways of doing this if you don't mind using other technologies. This is a matter of preference; but I've use Python, MySQL, and the excellent web.py framework for these sorts of backends.
For example, here's an example web service (some redundancies omitted...) using the combination of technologies described. I just run this on my server, and it takes care of url redirection and serves JSON from the db.
import web
import json
import MySQLdb
urls = (
"/equip/gruppo", "gruppo", # GET = get all gruppos, # POST = save gruppo
"/equip/frame", "frame"
)
class StatusCode:
(Success,SuccessNoRows,FailConnect,FailQuery,FailMissingParam,FailOther) = range(6);
# top-level class that handles db interaction
class APIObject:
def __init__(self):
self.object_dict = {} # top-level dictionary to be turned into JSON
self.rows = []
self.cursor = ""
self.conn = ""
def dbConnect(self):
try:
self.conn = MySQLdb.connect( host = 'localhost', user = 'my_api_user', passwd = 'api_user_pw', db = 'my_db')
self.cursor = self.conn.cursor(MySQLdb.cursors.DictCursor)
except:
self.object_dict['api_status'] = StatusCode.FailConnect
return False
else:
return True
def queryExecute(self,query):
try:
self.cursor.execute(query)
self.rows = self.cursor.fetchall()
except:
self.object_dict['api_status'] = StatusCode.FailQuery
return False
else:
return True
class gruppo(APIObject):
def GET(self):
web.header('Content-Type', 'application/json')
if self.dbConnect() == False:
return json.dumps(self.object_dict,sort_keys=True, indent=4)
else:
if self.queryExecute("SELECT * FROM gruppos") == False:
return json.dumps(self.object_dict,sort_keys=True, indent=4)
else:
self.object_dict['api_status'] = StatusCode.SuccessNoRows if self.rows.count == 0 else StatusCode.Success
data_list = []
for row in self.rows:
# create a dictionary with the required elements
d = {}
d['id'] = row['id']
d['maker'] = row['maker_name']
d['type'] = row['type_name']
# append to the object list
data_list.append(d)
self.object_dict['data'] = data_list
# return to the client
return json.dumps(self.object_dict,sort_keys=True, indent=4)