-
Notifications
You must be signed in to change notification settings - Fork 12
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
PyTauri #119
Comments
Can you explain here what you are requesting to happen? @AriBermeki |
Init Static Directorywithout fastapi serverwith headless = TrueI strongly assume that the problem lies in the headless.rs file. To solve the problem, one needs to implement a code, like the fastapi code shown underneath, It could be that this functionality is already implemented, but I'm not sure how to achieve it. I would like pywry to have a HTTP GET method that returns static files as a file response. This GET method should look for the requested file in a python directory. If the file exists, it should be returned as a file response; otherwise a 404 error code (not found) should be returned. This should be done as part of the default router example. Request example:<script src="/_next/static/main.js"></script>
<link rel="stylesheet" href="/_next/static/min.css"> Or<script src="/assets/main.js"></script>
<link rel="stylesheet" href="/assets/min.css"> Python example:from fastapi import FastAPI, HTTPException
from fastapi.responses import FileResponse
from pathlib import Path
app = FastAPI()
index_html_path = Path("path/to/index.html")
directory_ = Path("path/to/static/files")
app.mount("/static", StaticFiles(directory=directory_ , html=True), name="static")
@app.get("/")
async def get_index():
if not index_html_path.is_file():
raise HTTPException(status_code=404, detail="File not found")
return FileResponse(index_html_path, media_type='text/html')
@app.get("/{asset_path:path}")
async def get_assets(asset_path: str):
asset_file_path = directory_ / asset_path
if not asset_file_path.is_file():
raise HTTPException(status_code=404, detail="File not found")
return FileResponse(asset_file_path) maybe this code will be helpful for youtauri assets systemhttps://github.com/tauri-apps/tauri/blob/dev/core/tauri-utils/src/assets.rstauri html systemhttps://github.com/tauri-apps/tauri/blob/dev/core/tauri-utils/src/html.rs tauri mime_type systemhttps://github.com/tauri-apps/tauri/blob/dev/core/tauri-utils/src/mime_type.rsIPC communication between Rust and Python:It would be very helpful if json_data could forward events sent via IPC IPC example in Rust:use tokio::net::TcpListener;
use tokio::io::{AsyncReadExt, AsyncWriteExt};
#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
let listener = TcpListener::bind("127.0.0.1:8080").await?;
loop {
let (mut socket, _) = listener.accept().await?;
tokio::spawn(async move {
let mut buf = [0; 1024];
// In a loop, read data from the socket and write the data back.
loop {
let n = match socket.read(&mut buf).await {
// socket closed
Ok(n) if n == 0 => return,
Ok(n) => n,
Err(e) => {
eprintln!("failed to read from socket; err = {:?}", e);
return;
}
};
// Write the data back
if let Err(e) = socket.write_all(&buf[0..n]).await {
eprintln!("failed to write to socket; err = {:?}", e);
return;
}
}
});
}
}
IPC example in Python:import socket
def communicate_with_rust_server(message: str, server_ip: str = '127.0.0.1', server_port: int = 8080):
# Create a TCP/IP socket
sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
# Connect the socket to the server's port
server_address = (server_ip, server_port)
print(f'Connecting to {server_ip}:{server_port}')
sock.connect(server_address)
try:
# Send data
print(f'Sending: {message}')
sock.sendall(message.encode('utf-8'))
# Look for the response (we'll receive the same data back from the server)
amount_received = 0
amount_expected = len(message)
received_data = []
while amount_received < amount_expected:
data = sock.recv(1024)
amount_received += len(data)
received_data.append(data)
print(f'Received: {"".join([chunk.decode("utf-8") for chunk in received_data])}')
finally:
print('Closing connection')
sock.close()
# Example usage:
if __name__ == '__main__':
communicate_with_rust_server("Hello, Rust server!")
Event control between frontend and backend:When the frontend wants to trigger a Tao event, it sends the event name via IPC to Wry with a Pywry frontend command. this is an example of how to implement iterateJsonObjectAndAttachTaoEventHandler function in javascript but it must be done in rust const synthesizeTaoEventHandler = (event, e) => {
switch(event) {
case "onclick":
console.log("Clicked!", e);
return;
// Weitere Fälle hier hinzufügen
}
};
const iterateJsonObjectAndAttachTaoEventHandler = (json_object, eventList) => {
const event_object = { ...json_object };
for (const propName in event_object) {
if (eventList.includes(propName)) {
const eventTypeValue = event_object[propName];
event_object[propName] = (e) => synthesizeTaoEventHandler(eventTypeValue, e);
}
}
return event_object;
};
const jsonObject = {
event_type: "onclick",
event_props: {},
window_id: "value"
};
const eventList = ["onclick", "onmouseover"];
const taoevent = iterateJsonObjectAndAttachTaoEventHandler(jsonObject, eventList);
Rust examplei don't know if they have the same eefecteuse serde_json::Value;
fn synthesize_tao_event_handler(event: &str, e: &Value) {
match event {
"onclick" => {
println!("Clicked! {:?}", e);
}
// Add more cases here as needed
_ => {}
}
}
fn iterate_json_object_and_attach_tao_event_handler(
json_object: &[Value],
event_list: &[&str],
) -> Vec<Value> {
let mut event_object = json_object.to_vec(); // Make a mutable copy of the input
for obj in &mut event_object {
if let Some(event_type_value) = obj.get_mut("event_type") {
if let Some(event_type_str) = event_type_value.as_str() {
if event_list.contains(&event_type_str) {
let handler_value = serde_json::json!({
"handler": event_type_str
});
*event_type_value = handler_value;
}
}
}
}
event_object
}
fn main() {
let json_data = r#"
[
{
"event_type": "onclick",
"event_props": {
"widith": 800,
"height": 600
},
"window_id": 1
},
{
"event_type": "onclick",
"event_props": {
"widith": 800,
"height": 600
},
"window_id": 1
},
{
"event_type": "onclick",
"event_props": {
"widith": 800,
"height": 600
},
"window_id": 1
},
{
"event_type": "onclick",
"event_props": {
"widith": 800,
"height": 600
},
"window_id": 1
}
]
"#;
// Parse JSON data into a Vec<Value>
let json_object: Vec<Value> = serde_json::from_str(json_data).unwrap();
let event_list = vec!["onclick", "onmouseover"];
let taoevent = iterate_json_object_and_attach_tao_event_handler(&json_object, &event_list);
// Example usage of the handlers
for handler_obj in &taoevent {
if let Some(handler) = handler_obj.get("handler") {
if let Value::String(event_type_value) = handler {
synthesize_tao_event_handler(event_type_value, &Value::Null);
}
}
}
println!("{:?}", taoevent);
}
Rust functions for executing Python functions:We need two Rust functions that can call Python functions (e.g. startup, shutdown) These functions are useful and important to take Additional Note:I assume you have developed pywry for a specific purpose. In my view the purpose is to use Python features for desktop applications without having to use Rust. I am trying to link javascript files via pywry. This does not work for me. I get a file not found error. I believe there will be developers who will get a similar problem. Please help me to solve the problem and extend the functionality of IPC. I would like to send real-time data (via IPC) back and forth. My knowledge of Rust is almost zero, but I have experience in full-stack development and I know how web technology works in Python. I have experience with FastAPI, Flask, and Django. I believe Pywry has this ability without developing a Python web server, that requires a lot of work and runtime. I wrote these things so that we don't have to create an additional Python web server that runs in the background. |
I have solved the first problem (Init Static Directory)Your headless.rs file must have this response system. This system currently works for me without FastAPI only rust
cargo add mime_guess
use std::path::PathBuf;
use tao::{
event::{Event, WindowEvent},
event_loop::{ControlFlow, EventLoop},
window::WindowBuilder,
};
use wry::{
http::{header::CONTENT_TYPE, Request, Response},
WebViewBuilder,
};
use mime_guess::from_path;
fn main() -> wry::Result<()> {
let event_loop = EventLoop::new();
let window = WindowBuilder::new()
.build(&event_loop).unwrap();
#[cfg(any(
target_os = "windows",
target_os = "macos",
target_os = "ios",
target_os = "android"
))]
let builder = WebViewBuilder::new(&window);
#[cfg(not(any(
target_os = "windows",
target_os = "macos",
target_os = "ios",
target_os = "android"
)))]
let builder = {
use tao::platform::unix::WindowExtUnix;
use wry::WebViewBuilderExtUnix;
let vbox = window.default_vbox().unwrap();
WebViewBuilder::new_gtk(vbox)
};
// the variables must be accessible from the python side and initialization script must also be able to interact with this url
// with pywry.setup() function
let root_path = PathBuf::from("../out");
let frame_port = 3000;
let development = true;
let development_url = format!("http://localhost:{}", frame_port);
let index_page = "index.html";
let builder = builder
.with_devtools(true)
.with_hotkeys_zoom(true)
.with_custom_protocol(
"wry".into(),
move |request| {
match get_pywry_response_protocol(request, index_page, &root_path) {
Ok(r) => r.map(Into::into),
Err(e) => Response::builder()
.header(CONTENT_TYPE, "text/plain")
.status(500)
.body(e.to_string().as_bytes().to_vec())
.unwrap()
.map(Into::into),
}
},
);
let builder = if development {
builder.with_url(&development_url)
} else {
builder.with_url("wry://localhost")
};
let _webview = builder.build()?;
event_loop.run(move |event, _, control_flow| {
*control_flow = ControlFlow::Wait;
if let Event::WindowEvent {
event: WindowEvent::CloseRequested,
..
} = event
{
*control_flow = ControlFlow::Exit
}
});
}
fn get_pywry_response_protocol(
request: Request<Vec<u8>>,
index_page: &str,
root_path: &PathBuf
) -> Result<Response<Vec<u8>>, Box<dyn std::error::Error>> {
let path = request.uri().path();
// Read the file content from file path
let path = if path == "/" {
index_page
} else {
// Removing leading slash
&path[1..]
};
let full_path = std::fs::canonicalize(root_path.join(path))?;
let content = std::fs::read(&full_path)?;
#[cfg(target_os = "windows")]
let headers = "https://wry.localhost".to_string();
#[cfg(not(target_os = "windows"))]
let headers = "wry://localhost".to_string();
// Determine MIME type using `mime_guess`
let mime_type = from_path(&full_path).first_or_octet_stream();
Response::builder()
.header(CONTENT_TYPE, mime_type.as_ref())
.header("Access-Control-Allow-Origin", headers)
.header("Cache-Control", "no-cache, no-store, must-revalidate")
.header("Pragma", "no-cache")
.header("Expires", "0")
.header("Accept-Encoding", "gzip, compress, br, deflate")
.body(content)
.map_err(Into::into)
}
|
Why do not it in Mojo (faster language and closer to python) instead Python? |
If Mojo will support Pypi in the future you can import it from Pypi, Pywry has not behaved operatively on my statement that my Rust knowledge is zero and that's why they haven't answered until now and that's why I've been developing in Rust since my ISSUS, I'm building a ToolKit for it and doing one from the beginning with Pyo3 |
I'm testing this project https://docs.pyloid.com/ and I think it's a similar project to what you are doing, Pyloid is just starting but it looks very good, I'm thinking to collaborate with the development, and maybe in the future Pyloid will work with Mojo ;) |
it does not support asyncio, mine does and faster |
Do you have a repository for this project? maybe I can help or collaborate, I am interested in this project |
Do you have a WhatsApp number? |
|
Please contact me via email at [ [email protected] ]. I plan to develop a Python version of the Tauri framework. The attached screenshot shows the use of PyWry, Next.js and Vite. There are urgent tasks that need to be handled by PyWry.
The text was updated successfully, but these errors were encountered: