likes
comments
collection
share

将Geoserver服务打包到Tauri程序中使用

作者站长头像
站长
· 阅读数 5

GeoServer在Tauri中无感启动与使用

吃力不讨好的事情 PC端加载至少1G的tif文件到地图中展示 离谱 切片都不帮个忙 这不难为老实人么

将Geoserver服务打包到Tauri程序中使用


甲、环境Tauri跨端程序

前端

  • [✅] 得升级@tauri-apps/cli>=2.0.0-beta.0
  • [✅] - @tauri-apps/api >=2.0.0-beta.0

rust

  • [✅] 得升级tauri-build2.0.0-beta.10
  • [✅] - tauri 2.0.0-beta.13

乙、下载最新的Geoserver二进制文件

一定🏳️ 一定🏳️ 一定🏳️ 下载二进制文件Platform Independent Binary

Geoserver Platform Independent Binary


丙、 下载最低17版本的java

一定🏳️ 一定🏳️ 一定🏳️ 下载免安装解压即用的

java_17 zip


丁、 设置Tauri 打包文件

tauri.conf.json

 "resources": [
      "./resources/geoserver-main-latest-bin"
 ]

文件geoserver-main-latest-bin中需要包含下载解压的java_17 最终项目结构是

-src-tauri/resources/geoserver-main-latest-bin --bin --data_dir --etc --jdk_17 --lib --license --licenses --log --modules --resources --webapps --start.ini --start.jar --VERSION.txt


戍、rust执行终端命令唤起geoserver

1) 使用std::env::current_dir判断文件是否存在
    let binding = env::current_dir().unwrap().join("resources/geoserver-main-latest-bin");
    let flag = is_path_exists(binding.to_str().unwrap());
2) 使用std::process::Command执行终端命令
    //CREATE_NO_WINDOW 叮嘱此变量是设置终端命令执行时不创建终端窗口(仅限window)
    let binding = env::current_dir().unwrap().join("resources/geoserver-main-latest-bin");
    let java_path = binding.join(r"jdk_17/bin/java.exe");
    let jar_path = binding.join(r".\start.jar");
    const CREATE_NO_WINDOW: u32 = 0x08000000;
    let  command  = Command::new(java_path)
        .arg("-jar")
        .arg(jar_path)
        .current_dir(binding)
        .creation_flags(CREATE_NO_WINDOW)
        .spawn();
3) 使用std::net::UdpSocket::bind获取当前设备IP
fn get_local_ip() -> Option<IpAddr> {
    let socket = match std::net::UdpSocket::bind("0.0.0.0:0") {
        Ok(socket) => socket,
        Err(_) => return None,
    };

    match socket.connect("8.8.8.8:80") {
        Ok(()) => (),
        Err(_) => return None,
    }

    socket.local_addr().ok().map(|addr| addr.ip())
}

fn is_port_available(ip: IpAddr, port: u16) -> bool {
    let addr = SocketAddr::new(ip, port);
    TcpStream::connect(addr).is_ok()
}

#[tauri::command]
pub async fn get_localhost_ip() -> Result<CustomResult> {
    if let Some(ip) = get_local_ip() {
        println!("Local IP address: {}", ip);

        let port = 28080;
        if is_port_available(ip, port) {
            return Ok(CustomResult::new(true, 200, "Success", Some(json!({
                "ip": ip,
                "port": port
            }))));
        } else {
            return Err(CustomResult::new(false, 500, &format!("Port {} is not available", port), None));
        }
    } else {
        return Err(CustomResult::new(false, 500, "Failed to get local IP address", None));
    }
}

CustomResult是我自定义的内容返回格式,请自行处理


己、唤起服务

不在项目启动时唤起,单独开启子进程会阻塞主进程 在前端初始化时在进行IPC通信唤起 设置打开Geoserver时单独唤起一个webview

import { invokeGeoServerExist, invokeGeoServerStart, invokeGetLocalhostIp } from "@/ipc-apps/invoke.geoserver";
import { ResultMeta } from "@/types/result";
import { useEffect, useState } from "react";
import { WebviewWindow  } from '@tauri-apps/api/webviewWindow';

export const useGeoServerClient = () => {
    const [isExist, setExist] = useState<boolean>(false);

    const [isStart, setStart] = useState<boolean>(false);

    const [ipAddress, setIpAddress] = useState<{
        address: string,
        msg: string
    }>({
        address: '',
        msg: 'GeoServer服务未启动'
    })

    const queryGeoServer = async () => {
        invokeGeoServerExist().then((res: ResultMeta) => {
            console.log('是否存在 = ',res.success);
            if(res.success){
                setExist(true);
                invokeGeoServerStart().then((res: ResultMeta) => {
                    console.info('geoserver启动成功');
                    // res.success && setStart(true);
                })
            }
        })
    }
    const geoserverUrl = (_isStart: boolean, uri: string) => {
        if(!_isStart)return;
        const webview = new WebviewWindow("geoserver-window", {
            url: `${uri}/geoserver/index.html`,
            x: 0,
            y: 0,
            width: 1440,
            height: 1080,
            title: "GeoServer自启服务",
          });
        webview.once('tauri://created', function () {
        // webview 窗口成功创建
        console.log('成功');
        
        });

        webview.once('tauri://error', function (e) {
        // 创建窗口时出现错误
        console.log('错误, ', e);
        
        });
    }

    useEffect(() => {
        console.log("是否启动 = ", isExist);
        
        if(isExist){
            const _timer = setInterval(() => {
                invokeGetLocalhostIp().then(res => {
                    console.log('res =', res);
                    
                    if(res.success){
                        setStart(true)
                        const { 
                            ip, port
                        } = res.payload;
                        setIpAddress({
                            address: `http://${ip}:${port}`,
                            msg: 'GeoServer服务已启动'
                        })
                        clearInterval(_timer)
                    }else{
                        setIpAddress({
                            address: "",
                            msg: res.msg
                        })
                    }
                })
            }, 1000)
        }
    }, [isExist])



    return {
        isStart,
        ipAddress,
        isExist,
        queryGeoServer,
        geoserverUrl
    }
}

庚、得设置允许http使用

tauri.conf.json

"security": {
      "csp": null
    },