Commit 22b430de authored by Sergey Lyubka's avatar Sergey Lyubka

Using ctypes.WinDLL on Windows

parent 7d5eb279
...@@ -26,10 +26,10 @@ This module provides python binding for the Mongoose web server. ...@@ -26,10 +26,10 @@ This module provides python binding for the Mongoose web server.
There are two classes defined: There are two classes defined:
Connection: - wraps all functions that accept struct mg_connection pointer Connection: - wraps all functions that accept struct mg_connection pointer
as first argument. as first argument.
Mongoose: wraps all functions that accept struct mg_context pointer as Mongoose: wraps all functions that accept struct mg_context pointer as
first argument. first argument.
Creating Mongoose object automatically starts server, deleting object Creating Mongoose object automatically starts server, deleting object
automatically stops it. There is no need to call mg_start() or mg_stop(). automatically stops it. There is no need to call mg_start() or mg_stop().
...@@ -47,113 +47,115 @@ INIT_SSL = 3 ...@@ -47,113 +47,115 @@ INIT_SSL = 3
class mg_header(ctypes.Structure): class mg_header(ctypes.Structure):
"""A wrapper for struct mg_header.""" """A wrapper for struct mg_header."""
_fields_ = [ _fields_ = [
('name', ctypes.c_char_p), ('name', ctypes.c_char_p),
('value', ctypes.c_char_p), ('value', ctypes.c_char_p),
] ]
class mg_request_info(ctypes.Structure): class mg_request_info(ctypes.Structure):
"""A wrapper for struct mg_request_info.""" """A wrapper for struct mg_request_info."""
_fields_ = [ _fields_ = [
('user_data', ctypes.c_char_p), ('user_data', ctypes.c_char_p),
('request_method', ctypes.c_char_p), ('request_method', ctypes.c_char_p),
('uri', ctypes.c_char_p), ('uri', ctypes.c_char_p),
('http_version', ctypes.c_char_p), ('http_version', ctypes.c_char_p),
('query_string', ctypes.c_char_p), ('query_string', ctypes.c_char_p),
('remote_user', ctypes.c_char_p), ('remote_user', ctypes.c_char_p),
('log_message', ctypes.c_char_p), ('log_message', ctypes.c_char_p),
('remote_ip', ctypes.c_long), ('remote_ip', ctypes.c_long),
('remote_port', ctypes.c_int), ('remote_port', ctypes.c_int),
('status_code', ctypes.c_int), ('status_code', ctypes.c_int),
('is_ssl', ctypes.c_int), ('is_ssl', ctypes.c_int),
('num_headers', ctypes.c_int), ('num_headers', ctypes.c_int),
('http_headers', mg_header * 64), ('http_headers', mg_header * 64),
] ]
mg_callback_t = ctypes.CFUNCTYPE(ctypes.c_void_p, mg_callback_t = ctypes.CFUNCTYPE(ctypes.c_void_p,
ctypes.c_int, ctypes.c_int,
ctypes.c_void_p, ctypes.c_void_p,
ctypes.POINTER(mg_request_info)) ctypes.POINTER(mg_request_info))
class Connection(object): class Connection(object):
"""A wrapper class for all functions that take """A wrapper class for all functions that take
struct mg_connection * as the first argument.""" struct mg_connection * as the first argument."""
def __init__(self, mongoose, connection): def __init__(self, mongoose, connection):
self.m = mongoose self.m = mongoose
self.conn = ctypes.c_void_p(connection) self.conn = ctypes.c_void_p(connection)
def get_header(self, name): def get_header(self, name):
val = self.m.dll.mg_get_header(self.conn, name) val = self.m.dll.mg_get_header(self.conn, name)
return ctypes.c_char_p(val).value return ctypes.c_char_p(val).value
def get_var(self, data, name): def get_var(self, data, name):
size = data and len(data) or 0 size = data and len(data) or 0
buf = ctypes.create_string_buffer(size) buf = ctypes.create_string_buffer(size)
n = self.m.dll.mg_get_var(data, size, name, buf, size) n = self.m.dll.mg_get_var(data, size, name, buf, size)
return n >= 0 and buf or None return n >= 0 and buf or None
def printf(self, fmt, *args): def printf(self, fmt, *args):
val = self.m.dll.mg_printf(self.conn, fmt, *args) val = self.m.dll.mg_printf(self.conn, fmt, *args)
return ctypes.c_int(val).value return ctypes.c_int(val).value
def write(self, data): def write(self, data):
val = self.m.dll.mg_write(self.conn, data, len(data)) val = self.m.dll.mg_write(self.conn, data, len(data))
return ctypes.c_int(val).value return ctypes.c_int(val).value
def read(self, size): def read(self, size):
buf = ctypes.create_string_buffer(size) buf = ctypes.create_string_buffer(size)
n = self.m.dll.mg_read(self.conn, buf, size) n = self.m.dll.mg_read(self.conn, buf, size)
return n <= 0 and None or buf[:n] return n <= 0 and None or buf[:n]
def send_file(self, path): def send_file(self, path):
self.m.dll.mg_send_file(self.conn, path) self.m.dll.mg_send_file(self.conn, path)
class Mongoose(object): class Mongoose(object):
"""A wrapper class for Mongoose shared library.""" """A wrapper class for Mongoose shared library."""
def __init__(self, callback, **kwargs): def __init__(self, callback, **kwargs):
dll_extension = os.name == 'nt' and 'dll' or 'so' if os.name == 'nt':
self.dll = ctypes.CDLL('_mongoose.%s' % dll_extension) self.dll = ctypes.WinDLL('_mongoose.dll')
else:
self.dll.mg_start.restype = ctypes.c_void_p self.dll = ctypes.CDLL('_mongoose.so')
self.dll.mg_modify_passwords_file.restype = ctypes.c_int
self.dll.mg_read.restype = ctypes.c_int self.dll.mg_start.restype = ctypes.c_void_p
self.dll.mg_write.restype = ctypes.c_int self.dll.mg_modify_passwords_file.restype = ctypes.c_int
self.dll.mg_printf.restype = ctypes.c_int self.dll.mg_read.restype = ctypes.c_int
self.dll.mg_get_header.restype = ctypes.c_char_p self.dll.mg_write.restype = ctypes.c_int
self.dll.mg_get_var.restype = ctypes.c_int self.dll.mg_printf.restype = ctypes.c_int
self.dll.mg_get_cookie.restype = ctypes.c_int self.dll.mg_get_header.restype = ctypes.c_char_p
self.dll.mg_get_option.restype = ctypes.c_char_p self.dll.mg_get_var.restype = ctypes.c_int
self.dll.mg_get_cookie.restype = ctypes.c_int
if callback: self.dll.mg_get_option.restype = ctypes.c_char_p
# Create a closure that will be called by the shared library.
def func(event, connection, request_info): if callback:
# Wrap connection pointer into the connection # Create a closure that will be called by the shared library.
# object and call Python callback def func(event, connection, request_info):
conn = Connection(self, connection) # Wrap connection pointer into the connection
return callback(event, conn, request_info.contents) and 1 or 0 # object and call Python callback
conn = Connection(self, connection)
# Convert the closure into C callable object return callback(event, conn, request_info.contents) and 1 or 0
self.callback = mg_callback_t(func)
self.callback.restype = ctypes.c_char_p # Convert the closure into C callable object
else: self.callback = mg_callback_t(func)
self.callback = ctypes.c_void_p(0) self.callback.restype = ctypes.c_char_p
else:
args = [y for x in kwargs.items() for y in x] + [None] self.callback = ctypes.c_void_p(0)
options = (ctypes.c_char_p * len(args))(*args)
args = [y for x in kwargs.items() for y in x] + [None]
ret = self.dll.mg_start(self.callback, 0, options) options = (ctypes.c_char_p * len(args))(*args)
self.ctx = ctypes.c_void_p(ret)
ret = self.dll.mg_start(self.callback, 0, options)
def __del__(self): self.ctx = ctypes.c_void_p(ret)
"""Destructor, stop Mongoose instance."""
self.dll.mg_stop(self.ctx) def __del__(self):
"""Destructor, stop Mongoose instance."""
def get_option(self, name): self.dll.mg_stop(self.ctx)
return self.dll.mg_get_option(self.ctx, name)
def get_option(self, name):
return self.dll.mg_get_option(self.ctx, name)
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment