Python Wrapper (Not Complete)

* First Python Wrapper Commit v2.2.0 (Not Complete)
* Adding `windows_build.bat`
This commit is contained in:
Hassan DRAGA 2023-04-19 22:52:56 -04:00
parent 2de4a80867
commit 04b3ab7734
15 changed files with 206 additions and 150 deletions

3
.gitignore vendored
View File

@ -2,13 +2,12 @@
*.exe
*.ilk
*.pdb
*.lib
*.exp
*.res
*.out
*.o
*.def
*.obj
*.o
# IDE
.idea/

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

110
build/windows_build.bat Normal file
View File

@ -0,0 +1,110 @@
@echo off
set WEBUI_VERSION=2.2.0
set ARG1=%1
IF "%ARG1%"=="debug" (
set MSVC_CMD=nmake debug
set GCC_CMD=mingw32-make debug
) else (
set MSVC_CMD=nmake
set GCC_CMD=mingw32-make
)
echo.
echo WebUI v%WEBUI_VERSION% Build Script
echo Platform: Microsoft Windows x64
echo Compiler: MSVC and GCC
Set RootPath=%CD%\..\
cd "%RootPath%"
echo.
echo - - [Build MSVC] - - - - - - - - - - - - - -
REM Build WebUI Library using MSVC
cd "%RootPath%"
cd "build\Windows\MSVC"
%MSVC_CMD%
echo.
echo - - [Build GCC] - - - - - - - - - - - - - -
echo.
REM Build WebUI Library using GCC
cd "%RootPath%"
cd "build\Windows\GCC"
%GCC_CMD%
echo.
echo - - [Build TCC] - - - - - - - - - - - - - -
echo.
REM Build WebUI Library using TCC
cd "%RootPath%"
cd "build\Windows\TCC"
%GCC_CMD%
echo.
echo - - [Copy Libs] - - - - - - - - - - - - - -
echo.
cd "%RootPath%"
REM Golang
copy /Y "include\webui.h" "examples\Go\hello_world\webui\webui.h"
copy /Y "build\Windows\GCC\libwebui-2-static-x64.a" "examples\Go\hello_world\webui\libwebui-2-static-x64.a"
REM Deno
copy /Y "build\Windows\MSVC\webui-2-x64.dll" "examples\TypeScript\Deno\webui-2-x64.dll"
REM Python
copy /Y "build\Windows\MSVC\webui-2-x64.dll" "examples\Python\PyPI\Package\src\webui\webui-2-x64.dll"
echo.
IF "%ARG1%"=="" (
echo - - [Copy Release Libs] - - - - - - - - - -
echo.
REM Release Windows Include
copy /Y "include\webui.h" "Release\Windows\include\webui.h"
REM Release Windows MSVC
copy /Y "build\Windows\MSVC\webui-2-x64.dll" "Release\Windows\MSVC\webui-2-x64.dll"
copy /Y "build\Windows\MSVC\webui-2-x64.lib" "Release\Windows\MSVC\webui-2-x64.lib"
copy /Y "build\Windows\MSVC\webui-2-static-x64.lib" "Release\Windows\MSVC\webui-2-static-x64.lib"
REM Release Windows GCC
copy /Y "build\Windows\GCC\webui-2-x64.dll" "Release\Windows\GCC\webui-2-x64.dll"
copy /Y "build\Windows\GCC\libwebui-2-static-x64.a" "Release\Windows\GCC\libwebui-2-static-x64.a"
REM Release Windows TCC
copy /Y "build\Windows\TCC\webui-2-x64.dll" "Release\Windows\TCC\webui-2-x64.dll"
copy /Y "build\Windows\TCC\libwebui-2-static-x64.a" "Release\Windows\TCC\libwebui-2-static-x64.a"
copy /Y "build\Windows\TCC\webui-2-x64.def" "Release\Windows\TCC\webui-2-x64.def"
echo.
echo - - [Compress Release Folder] - - - - - - - -
echo.
set TAR_OUT=webui-windows-x64-v%WEBUI_VERSION%.zip
cd "Release"
tar.exe -c -f %TAR_OUT% Windows
cd "%RootPath%"
echo.
echo - - [Clean] - - - - - - - - - - - - - - - - -
DEL /Q /F /S "*.exe" >nul 2>&1
DEL /Q /F /S "*.o" >nul 2>&1
DEL /Q /F /S "*.exp" >nul 2>&1
DEL /Q /F /S "*.pdb" >nul 2>&1
DEL /Q /F /S "*.ilk" >nul 2>&1
DEL /Q /F /S "*.obj" >nul 2>&1
DEL /Q /F /S "*.res" >nul 2>&1
DEL /Q /F /S "*.bak" >nul 2>&1
DEL /Q /F /S "*.DS_Store" >nul 2>&1
)
cd "build"

Binary file not shown.

View File

@ -26,46 +26,32 @@ PTR_PTR_CHAR = ctypes.POINTER(PTR_CHAR)
# Event
class event:
window_id = 0
element_name = ""
data = ""
window = None
c_window = None
# WebUI C-Struct
class webui_script_interface_t(ctypes.Structure):
_fields_ = [
("script", c_char_p),
("timeout", c_uint),
("error", c_bool),
("length", c_uint),
("data", c_char_p)
]
Window = None
EventType = 0
Element = ""
Data = ""
# JavaScript
class javascript:
script = ""
timeout = 10
error = False
length = 0
data = ""
Error = False
Response = ""
# Scripts Runtime
class runtime:
none = 0
deno = 1
nodejs = 2
Deno = 1
Nodejs = 2
# The window class
class window:
window = None
window_id = None
c_events = None
cb_fun_list = [64]
cb_fun_list = {}
def __init__(self):
global WebUI
@ -82,16 +68,18 @@ class window:
webui_wrapper = WebUI.webui_new_window
webui_wrapper.restype = c_void_p
self.window = c_void_p(webui_wrapper())
# Get the window unique ID
self.window_id = int(
WebUI.webui_interface_get_window_id(
self.window))
# Initializing events() to be used by
# WebUI library as a callback
py_fun = ctypes.CFUNCTYPE(
ctypes.c_void_p,
ctypes.c_uint,
ctypes.c_uint,
ctypes.c_char_p,
ctypes.c_void_p,
ctypes.c_char_p,
PTR_PTR_CHAR)
ctypes.c_void_p, # Window
ctypes.c_uint, # EventType
ctypes.c_char_p, # Element
ctypes.c_char_p, # Data
ctypes.c_char_p) # Response
self.c_events = py_fun(self.events)
except OSError as e:
print(
@ -105,26 +93,22 @@ class window:
# WebUI.webui_close(self.window)
def events(self, element_id, window_id,
element_name, window, data, response):
if self.cb_fun_list[int(element_id)] is None:
def events(self, window, event_type,
element, data, response):
if self.cb_fun_list[self.window_id][element] is None:
print('WebUI Error: Callback is None.')
return
# Create event
e = event()
e.element_id = int(element_id)
e.window_id = int(window_id)
e.data = data.decode('utf-8')
e.element_name = element_name.decode('utf-8')
e.window = self
e.c_window = window
e.Window = self
e.EventType = int(event_type)
e.Element = element.decode('utf-8')
e.Data = data.decode('utf-8')
# User callback
cb_res = str(self.cb_fun_list[element_id](e))
cb_res = str(self.cb_fun_list[self.window_id][element](e))
cb_res_encode = cb_res.encode('utf-8')
# Allocate a new memory
buffer = ctypes.create_string_buffer(cb_res_encode)
# Set the response
response[0] = buffer
WebUI.webui_interface_bind(response, cb_res_encode)
def bind(self, element, func):
@ -135,15 +119,16 @@ class window:
if WebUI is None:
err_library_not_found('bind')
return
cb_index = int(
WebUI.webui_interface_bind(
self.window,
element.encode('utf-8'),
self.c_events))
self.cb_fun_list.insert(cb_index, func)
# Bind
WebUI.webui_interface_bind(
self.window,
element.encode('utf-8'),
self.c_events)
# Add CB to the list
self.cb_fun_list[self.window_id] = {element: func}
def show(self, html="<html></html>"):
def show(self, content="<html></html>"):
global WebUI
if self.window is None:
err_window_is_none('show')
@ -151,59 +136,31 @@ class window:
if WebUI is None:
err_library_not_found('show')
return
WebUI.webui_show(self.window, html.encode('utf-8'))
# Show the window
WebUI.webui_show(self.window, content.encode('utf-8'))
def open(self, url, browser=0):
def set_runtime(self, rt=runtime.deno):
global WebUI
if self.window is None:
err_window_is_none('open')
err_window_is_none('set_runtime')
return
if WebUI is None:
err_library_not_found('open')
err_library_not_found('set_runtime')
return
WebUI.webui_open(self.window,
url.encode('utf-8'), ctypes.c_uint(browser))
def script_runtime(self, rt=runtime.deno):
global WebUI
if self.window is None:
err_window_is_none('script_runtime')
return
if WebUI is None:
err_library_not_found('script_runtime')
return
WebUI.webui_script_runtime(self.window,
WebUI.webui_set_runtime(self.window,
ctypes.c_uint(rt))
def new_server(self, path=""):
def set_multi_access(self, status=False):
global WebUI
if self.window is None:
err_window_is_none('new_server')
err_window_is_none('set_multi_access')
return
if WebUI is None:
err_library_not_found('new_server')
err_library_not_found('set_multi_access')
return
webui_wrapper = None
webui_wrapper = WebUI.webui_new_server
webui_wrapper.argtypes = [c_void_p, c_void_p]
webui_wrapper.restype = c_char_p
url = c_char_p(webui_wrapper(self.window,
path.encode('utf-8'))).value.decode('utf-8')
return url
def multi_access(self, status=False):
global WebUI
if self.window is None:
err_window_is_none('multi_access')
return
if WebUI is None:
err_library_not_found('multi_access')
return
WebUI.webui_multi_access(self.window,
WebUI.webui_set_multi_access(self.window,
ctypes.c_bool(status))
@ -215,23 +172,15 @@ class window:
WebUI.webui_close(self.window)
def is_any_window_running(self):
global WebUI
if WebUI is None:
err_library_not_found('close')
return
r = bool(WebUI.webui_is_any_window_running())
return r
def is_shown(self):
global WebUI
if WebUI is None:
err_library_not_found('close')
err_library_not_found('is_shown')
return
r = bool(WebUI.webui_is_shown(self.window))
return r
def run_js(self, script, timeout=0) -> javascript:
def script(self, script, timeout=0, response_size=(1024 * 8)) -> javascript:
global WebUI
if self.window is None:
err_window_is_none('show')
@ -239,27 +188,20 @@ class window:
if WebUI is None:
err_library_not_found('show')
return
# Create Struct
js = webui_script_interface_t()
# Initializing
js.script = ctypes.c_char_p(script.encode('utf-8'))
js.timeout = ctypes.c_uint(timeout)
js.error = ctypes.c_bool(False)
js.length = ctypes.c_uint(0)
js.data = ctypes.c_char_p("".encode('utf-8'))
# Create Buffer
buffer = ctypes.create_string_buffer(response_size)
buffer.value = b""
# Create a pointer to the buffer
buffer_ptr = ctypes.pointer(buffer)
# Run JavaScript
status = bool(WebUI.webui_script(self.window,
ctypes.c_char_p(script.encode('utf-8')),
ctypes.c_uint(timeout), buffer_ptr,
ctypes.c_uint(response_size)))
# Initializing Result
res = javascript()
res.script = script
res.timeout = timeout
res.error = True
res.length = 7
res.data = "UNKNOWN"
# Run JavaScript
WebUI.webui_script_interface_struct(self.window,
ctypes.byref(js))
res.length = int(js.length)
res.data = js.data.decode('utf-8')
res.error = js.error
res.data = buffer.value.decode('utf-8')
res.error = status
return res
@ -355,7 +297,7 @@ def is_app_running():
if WebUI is None:
err_library_not_found('is_app_running')
return
r = bool(WebUI.webui_is_app_running())
r = bool(WebUI.webui_interface_is_app_running())
return r

View File

@ -1,5 +1,5 @@
# This script is for debugging & development of the WebUI Python wrapper
# The source code is located at 'webui/examples/Python/PyPI/Package/src/webui/webui.py'
# This script is for debugging & the development of the WebUI Python wrapper.
# The wrapper source code is located at 'webui/examples/Python/PyPI/Package/src/webui/webui.py'
# [!] Make sure to remove the WebUI package
# pip uninstall webui2
@ -10,16 +10,14 @@ sys.path.append('Package/src/webui')
import webui
# Use the local WebUI Dynamic lib
# For instructions on compiling it please visit:
# https://github.com/alifcommunity/webui/tree/main/build
webui.set_library_path('../../../build/Windows/GCC')
webui.set_library_path('../../../build/Windows/MSVC')
# HTML
html = """
<!DOCTYPE html>
<html>
<head>
<title>WebUI 2 - Python Debug & Development</title>
<title>WebUI 2 - Python Wrapper Test</title>
<style>
body {
color: white;
@ -33,52 +31,58 @@ html = """
</style>
</head>
<body>
<h2>Python Debug & Development</h2>
<h2>Python Wrapper Test</h2>
<br>
<input type="text" id="MyInput" OnKeyUp="document.getElementById('err').innerHTML='&nbsp;';" autocomplete="off" value=\"2\">
<br>
<h3 id="err" style="color: #dbdd52">&nbsp;</h3>
<br>
<button id="TestID">Test Python-To-JS</button>
<button id="P2JS">Test Python-To-JS</button>
<button OnClick="MyJS();">Test JS-To-Python</button>
<button id="ExitID">Exit</button>
<script>
function MyJS() {
const number = document.getElementById('MyInput').value;
var result = webui_fn('Test2', number);
var result = webui_fn('JS2P', number);
document.getElementById('MyInput').value = result;
}
</script>
</body></html>
"""
def test(e : webui.event):
print('Element_id: ' + str(e.element_id))
print('Window_id: ' + str(e.window_id))
print('Element_name: ' + e.element_name)
def all_events(e : webui.event):
print('Function: all_events()')
print('Element: ' + e.Element)
print('EventType: ' + e.EventType)
print('Data: ' + e.Data)
def python_to_js(e : webui.event):
print('Function: python_to_js()')
print('Element: ' + e.Element)
print('EventType: ' + e.EventType)
print('Data: ' + e.Data)
# Run JavaScript to get the password
res = e.window.run_js("return document.getElementById('MyInput').value;")
res = e.window.script("return document.getElementById('MyInput').value;")
# Check for any error
if res.error is True:
print("JavaScript Error -> Output: [" + res.data + "]")
else:
print("JavaScript OK -> Output: [" + res.data + "]")
def test2(e : webui.event):
print('Element_id: ' + str(e.element_id))
print('Window_id: ' + str(e.window_id))
print('Element_name: ' + e.element_name)
print('Data: ' + e.data)
def js_to_python(e : webui.event):
print('Function: js_to_python()')
print('Element: ' + e.Element)
print('EventType: ' + e.EventType)
print('Data: ' + e.Data)
v = int(e.data)
v = v * 2
return v
def close(e : webui.event):
print('Element_id: ' + str(e.element_id))
print('Window_id: ' + str(e.window_id))
print('Element_name: ' + e.element_name)
def exit(e : webui.event):
print('Function: exit()')
print('Element: ' + e.Element)
print('EventType: ' + e.EventType)
print('Data: ' + e.Data)
webui.exit()
def main():
@ -87,9 +91,10 @@ def main():
MyWindow = webui.window()
# Bind am HTML element ID with a python function
MyWindow.bind('', test)
MyWindow.bind('Test2', test2)
MyWindow.bind('ExitID', close)
MyWindow.bind('', all_events)
MyWindow.bind('P2JS', python_to_js)
MyWindow.bind('JS2P', js_to_python)
MyWindow.bind('Exit', exit)
# Show the window
MyWindow.show(html)

View File

@ -177,9 +177,9 @@ WEBUI_EXPORT void webui_return_string(webui_event_t* e, char* s);
WEBUI_EXPORT void webui_return_bool(webui_event_t* e, bool b);
// -- Interface -----------------------
// Bind a specific html element click event with a function. Empty element means all events. This replace webui_bind().
// Bind a specific html element click event with a function. Empty element means all events. This replace webui_bind(). The func is (Window, EventType, Element, Data, Response)
WEBUI_EXPORT unsigned int webui_interface_bind(void* window, const char* element, void (*func)(void*, unsigned int, char*, char*, char*));
// When using `webui_interface_bind()` you need this function to easily set your response.
// When using `webui_interface_bind()` you need this function to easily set your callback response.
WEBUI_EXPORT void webui_interface_set_response(char* ptr, const char* response);
// Check if the app still running or not. This replace webui_wait().
WEBUI_EXPORT bool webui_interface_is_app_running(void);