0.1.1
This commit is contained in:
@@ -1,6 +1,6 @@
|
|||||||
[package]
|
[package]
|
||||||
name = "tauri-video03"
|
name = "tauri-video03"
|
||||||
version = "0.1.0"
|
version = "0.1.1"
|
||||||
description = "A Tauri Video App"
|
description = "A Tauri Video App"
|
||||||
authors = ["sinus@sasedev.net"]
|
authors = ["sinus@sasedev.net"]
|
||||||
edition = "2024"
|
edition = "2024"
|
||||||
@@ -28,10 +28,11 @@ serde = { version = "^1.0", features = ["derive"] }
|
|||||||
serde_json = { version = "^1.0", features = [] }
|
serde_json = { version = "^1.0", features = [] }
|
||||||
tauri = { version = "^2.10", features = ["default"] }
|
tauri = { version = "^2.10", features = ["default"] }
|
||||||
tauri-plugin-opener = { version = "^2.5", features = [] }
|
tauri-plugin-opener = { version = "^2.5", features = [] }
|
||||||
|
tauri-plugin-websocket = "2"
|
||||||
tokio = { version = "^1.50", features = ["full"] }
|
tokio = { version = "^1.50", features = ["full"] }
|
||||||
tokio-tungstenite = { version = "^0.29", features = ["rustls", "tokio-rustls", "url"] }
|
tokio-tungstenite = { version = "^0.29", features = ["rustls", "tokio-rustls", "url"] }
|
||||||
tracing = { version = "^0.1", features = ["async-await", "log"] }
|
tracing = { version = "^0.1", features = ["async-await", "log"] }
|
||||||
tracing-subscriber = { version = "^0.3", features = ["ansi", "env-filter", "chrono", "serde", "json"] }
|
tracing-subscriber = { version = "^0.3", features = ["ansi", "env-filter", "chrono", "serde", "json"] }
|
||||||
ts-rs = { version = "^12.0", features = [] }
|
ts-rs = { version = "^12.0", features = [] }
|
||||||
uuid = { version = "^1.23", features = [] }
|
uuid = { version = "^1.23", features = ["v4"] }
|
||||||
webrtc = { version = "^0.17", features = [] }
|
webrtc = { version = "^0.17", features = [] }
|
||||||
|
|||||||
@@ -2,9 +2,12 @@
|
|||||||
"$schema": "../gen/schemas/desktop-schema.json",
|
"$schema": "../gen/schemas/desktop-schema.json",
|
||||||
"identifier": "default",
|
"identifier": "default",
|
||||||
"description": "Capability for the main window",
|
"description": "Capability for the main window",
|
||||||
"windows": ["main"],
|
"windows": [
|
||||||
|
"main"
|
||||||
|
],
|
||||||
"permissions": [
|
"permissions": [
|
||||||
"core:default",
|
"core:default",
|
||||||
"opener:default"
|
"opener:default",
|
||||||
|
"websocket:default"
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
198
frontend/chat.ts
Normal file
198
frontend/chat.ts
Normal file
@@ -0,0 +1,198 @@
|
|||||||
|
import WebSocket from "@tauri-apps/plugin-websocket";
|
||||||
|
import { PeerInfo } from './ts/bindings/PeerInfo';
|
||||||
|
import { ClientWsMessage } from './ts/bindings/ClientWsMessage';
|
||||||
|
import { ServerWsMessage } from './ts/bindings/ServerWsMessage';
|
||||||
|
|
||||||
|
type RemoveListener = (() => void) | null;
|
||||||
|
|
||||||
|
export class LocalSignallingClient {
|
||||||
|
private socket: WebSocket | null = null;
|
||||||
|
private removeListener: RemoveListener = null;
|
||||||
|
private myPeerId: string | null = null;
|
||||||
|
private peers: PeerInfo[] = [];
|
||||||
|
|
||||||
|
constructor(
|
||||||
|
private readonly displayName: string,
|
||||||
|
private readonly onLog: (message: string) => void,
|
||||||
|
private readonly onPeers: (peers: PeerInfo[]) => void,
|
||||||
|
private readonly onChat: (line: string) => void,
|
||||||
|
) {}
|
||||||
|
|
||||||
|
public async connect(): Promise<void> {
|
||||||
|
if (this.socket !== null) {
|
||||||
|
this.onLog("signalling already connected");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const url = "ws://127.0.0.1:3012";
|
||||||
|
|
||||||
|
this.onLog(`connecting to ${url}`);
|
||||||
|
|
||||||
|
let socket: WebSocket;
|
||||||
|
try {
|
||||||
|
socket = await WebSocket.connect(url);
|
||||||
|
} catch (error) {
|
||||||
|
throw new Error(`websocket connection failed: ${String(error)}`);
|
||||||
|
}
|
||||||
|
|
||||||
|
this.socket = socket;
|
||||||
|
|
||||||
|
const removeListener = socket.addListener((message) => {
|
||||||
|
if (message.type === "Text") {
|
||||||
|
this.handleServerMessage(message.data);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (message.type === "Close") {
|
||||||
|
this.onLog("signalling disconnected");
|
||||||
|
this.cleanupDisconnectedState();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (message.type === "Binary") {
|
||||||
|
this.onLog("unexpected binary websocket message");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
this.removeListener = removeListener;
|
||||||
|
|
||||||
|
this.onLog("signalling connected");
|
||||||
|
|
||||||
|
await this.send({
|
||||||
|
type: "hello",
|
||||||
|
display_name: this.displayName,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
public async disconnect(): Promise<void> {
|
||||||
|
if (this.socket === null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const socket = this.socket;
|
||||||
|
|
||||||
|
if (this.removeListener !== null) {
|
||||||
|
this.removeListener();
|
||||||
|
this.removeListener = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
this.socket = null;
|
||||||
|
|
||||||
|
try {
|
||||||
|
await socket.disconnect();
|
||||||
|
} catch (error) {
|
||||||
|
this.onLog(`disconnect error: ${String(error)}`);
|
||||||
|
}
|
||||||
|
|
||||||
|
this.cleanupDisconnectedState();
|
||||||
|
}
|
||||||
|
|
||||||
|
public async sendChat(text: string): Promise<void> {
|
||||||
|
await this.send({
|
||||||
|
type: "chat_send",
|
||||||
|
text,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
public getMyPeerId(): string | null {
|
||||||
|
return this.myPeerId;
|
||||||
|
}
|
||||||
|
|
||||||
|
public getPeers(): PeerInfo[] {
|
||||||
|
return [...this.peers];
|
||||||
|
}
|
||||||
|
|
||||||
|
private async send(message: ClientWsMessage): Promise<void> {
|
||||||
|
if (this.socket === null) {
|
||||||
|
this.onLog("cannot send: signalling not connected");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const payload = JSON.stringify(message);
|
||||||
|
|
||||||
|
try {
|
||||||
|
await this.socket.send(payload);
|
||||||
|
} catch (error) {
|
||||||
|
this.onLog(`send failed: ${String(error)}`);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private cleanupDisconnectedState(): void {
|
||||||
|
this.socket = null;
|
||||||
|
this.myPeerId = null;
|
||||||
|
this.peers = [];
|
||||||
|
this.onPeers([]);
|
||||||
|
}
|
||||||
|
|
||||||
|
private handleServerMessage(raw: string): void {
|
||||||
|
let message: ServerWsMessage;
|
||||||
|
|
||||||
|
try {
|
||||||
|
message = JSON.parse(raw) as ServerWsMessage;
|
||||||
|
} catch (error) {
|
||||||
|
this.onLog(`invalid server message: ${String(error)}`);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
switch (message.type) {
|
||||||
|
case "welcome":
|
||||||
|
this.myPeerId = message.peer_id;
|
||||||
|
this.onLog(`welcome peer_id=${message.peer_id}`);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case "peer_list":
|
||||||
|
this.peers = message.peers;
|
||||||
|
this.onPeers([...this.peers]);
|
||||||
|
this.onLog(`peer_list received (${message.peers.length})`);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case "peer_joined":
|
||||||
|
this.peers = mergePeer(this.peers, message.peer);
|
||||||
|
this.onPeers([...this.peers]);
|
||||||
|
this.onLog(`peer joined: ${message.peer.display_name}`);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case "peer_left":
|
||||||
|
this.peers = this.peers.filter((peer) => peer.peer_id !== message.peer_id);
|
||||||
|
this.onPeers([...this.peers]);
|
||||||
|
this.onLog(`peer left: ${message.peer_id}`);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case "chat_receive":
|
||||||
|
this.onChat(`${message.from_display_name}: ${message.text}`);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case "offer":
|
||||||
|
this.onLog(`offer received from ${message.from_peer_id}`);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case "answer":
|
||||||
|
this.onLog(`answer received from ${message.from_peer_id}`);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case "ice_candidate":
|
||||||
|
this.onLog(`ice candidate received from ${message.from_peer_id}`);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case "pong":
|
||||||
|
this.onLog("pong");
|
||||||
|
break;
|
||||||
|
|
||||||
|
case "error":
|
||||||
|
this.onLog(`server error: ${message.message}`);
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
this.onLog(`unhandled server message: ${raw}`);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function mergePeer(peers: PeerInfo[], incoming: PeerInfo): PeerInfo[] {
|
||||||
|
const next = peers.filter((peer) => peer.peer_id !== incoming.peer_id);
|
||||||
|
next.push(incoming);
|
||||||
|
next.sort((a, b) => a.display_name.localeCompare(b.display_name));
|
||||||
|
return next;
|
||||||
|
}
|
||||||
@@ -6,12 +6,43 @@
|
|||||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||||
<meta http-equiv="Content-Security-Policy"
|
<meta http-equiv="Content-Security-Policy"
|
||||||
content="default-src 'self'; script-src 'self'; style-src 'self' 'unsafe-inline'; img-src 'self' data: blob:; connect-src 'self';" />
|
content="default-src 'self'; script-src 'self'; style-src 'self' 'unsafe-inline'; img-src 'self' data: blob:; connect-src 'self';" />
|
||||||
<title>Tauri GST Record + Preview</title>
|
<title>Tauri GST Signalling + Chat</title>
|
||||||
</head>
|
</head>
|
||||||
|
|
||||||
<body>
|
<body>
|
||||||
<main class="container">
|
<main class="container">
|
||||||
<h1>POC 2 - Recording + Preview</h1>
|
<h1>POC 3 - Chat</h1>
|
||||||
|
|
||||||
|
<section class="card">
|
||||||
|
<h2>Signalling + Chat</h2>
|
||||||
|
|
||||||
|
<div class="actions">
|
||||||
|
<input id="chat-display-name" type="text" placeholder="Display name"
|
||||||
|
value="sinus" />
|
||||||
|
<button id="chat-connect-btn" type="button">Connect
|
||||||
|
signalling</button>
|
||||||
|
<button id="chat-disconnect-btn" type="button" disabled>Disconnect</button>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="chat-grid">
|
||||||
|
<div>
|
||||||
|
<h3>Peers</h3>
|
||||||
|
<pre id="chat-peers">[]</pre>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div>
|
||||||
|
<h3>Logs</h3>
|
||||||
|
<pre id="chat-logs">Ready.</pre>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="actions">
|
||||||
|
<input id="chat-input" type="text" placeholder="Message" />
|
||||||
|
<button id="chat-send-btn" type="button" disabled>Send chat</button>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<pre id="chat-messages">No messages yet.</pre>
|
||||||
|
</section>
|
||||||
|
|
||||||
<section class="card">
|
<section class="card">
|
||||||
<h2>Video Preview</h2>
|
<h2>Video Preview</h2>
|
||||||
|
|||||||
107
frontend/main.ts
107
frontend/main.ts
@@ -2,6 +2,8 @@
|
|||||||
import { invoke } from "@tauri-apps/api/core";
|
import { invoke } from "@tauri-apps/api/core";
|
||||||
import { AvStartResponse } from './ts/bindings/AvStartResponse';
|
import { AvStartResponse } from './ts/bindings/AvStartResponse';
|
||||||
import { AvStopResponse } from './ts/bindings/AvStopResponse';
|
import { AvStopResponse } from './ts/bindings/AvStopResponse';
|
||||||
|
import { LocalSignallingClient } from "./chat";
|
||||||
|
import { PeerInfo } from './ts/bindings/PeerInfo';
|
||||||
|
|
||||||
type Mode = "idle" | "audio" | "video" | "av";
|
type Mode = "idle" | "audio" | "video" | "av";
|
||||||
|
|
||||||
@@ -19,6 +21,15 @@ const avStatus = document.querySelector<HTMLElement>("#av-status");
|
|||||||
|
|
||||||
const previewElement = document.querySelector<HTMLImageElement>("#video-preview");
|
const previewElement = document.querySelector<HTMLImageElement>("#video-preview");
|
||||||
|
|
||||||
|
const chatDisplayNameInput = document.querySelector<HTMLInputElement>("#chat-display-name");
|
||||||
|
const chatConnectBtn = document.querySelector<HTMLButtonElement>("#chat-connect-btn");
|
||||||
|
const chatDisconnectBtn = document.querySelector<HTMLButtonElement>("#chat-disconnect-btn");
|
||||||
|
const chatInput = document.querySelector<HTMLInputElement>("#chat-input");
|
||||||
|
const chatSendBtn = document.querySelector<HTMLButtonElement>("#chat-send-btn");
|
||||||
|
const chatPeers = document.querySelector<HTMLElement>("#chat-peers");
|
||||||
|
const chatLogs = document.querySelector<HTMLElement>("#chat-logs");
|
||||||
|
const chatMessages = document.querySelector<HTMLElement>("#chat-messages");
|
||||||
|
|
||||||
if (
|
if (
|
||||||
startAudioBtn === null ||
|
startAudioBtn === null ||
|
||||||
stopAudioBtn === null ||
|
stopAudioBtn === null ||
|
||||||
@@ -29,7 +40,15 @@ if (
|
|||||||
startAvBtn === null ||
|
startAvBtn === null ||
|
||||||
stopAvBtn === null ||
|
stopAvBtn === null ||
|
||||||
avStatus === null ||
|
avStatus === null ||
|
||||||
previewElement === null
|
previewElement === null ||
|
||||||
|
chatDisplayNameInput === null ||
|
||||||
|
chatConnectBtn === null ||
|
||||||
|
chatDisconnectBtn === null ||
|
||||||
|
chatInput === null ||
|
||||||
|
chatSendBtn === null ||
|
||||||
|
chatPeers === null ||
|
||||||
|
chatLogs === null ||
|
||||||
|
chatMessages === null
|
||||||
) {
|
) {
|
||||||
throw new Error("missing UI elements");
|
throw new Error("missing UI elements");
|
||||||
}
|
}
|
||||||
@@ -320,3 +339,89 @@ stopAvBtn.addEventListener("click", async () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
setCurrentMode("idle");
|
setCurrentMode("idle");
|
||||||
|
|
||||||
|
let signallingClient: LocalSignallingClient | null = null;
|
||||||
|
|
||||||
|
function appendChatLog(line: string): void {
|
||||||
|
if (chatLogs) {
|
||||||
|
const current = chatLogs.textContent ?? "";
|
||||||
|
chatLogs.textContent = `${current}\n${line}`.trim();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function appendChatMessage(line: string): void {
|
||||||
|
if (chatMessages) {
|
||||||
|
const current = chatMessages.textContent ?? "";
|
||||||
|
chatMessages.textContent = `${current}\n${line}`.trim();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function updatePeerList(peers: PeerInfo[]): void {
|
||||||
|
if (chatPeers)
|
||||||
|
chatPeers.textContent = JSON.stringify(peers, null, 2);
|
||||||
|
}
|
||||||
|
|
||||||
|
function setChatConnected(connected: boolean): void {
|
||||||
|
if (chatConnectBtn)
|
||||||
|
chatConnectBtn.disabled = connected;
|
||||||
|
if (chatDisconnectBtn)
|
||||||
|
chatDisconnectBtn.disabled = !connected;
|
||||||
|
if (chatSendBtn)
|
||||||
|
chatSendBtn.disabled = !connected;
|
||||||
|
}
|
||||||
|
|
||||||
|
chatConnectBtn.addEventListener("click", async () => {
|
||||||
|
if (signallingClient !== null) {
|
||||||
|
appendChatLog("signalling client already exists");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const displayName = (chatDisplayNameInput.value || "").trim() || "anonymous";
|
||||||
|
|
||||||
|
const client = new LocalSignallingClient(
|
||||||
|
displayName,
|
||||||
|
(line) => appendChatLog(line),
|
||||||
|
(peers) => updatePeerList(peers),
|
||||||
|
(line) => appendChatMessage(line),
|
||||||
|
);
|
||||||
|
|
||||||
|
try {
|
||||||
|
await client.connect();
|
||||||
|
signallingClient = client;
|
||||||
|
setChatConnected(true);
|
||||||
|
} catch (error) {
|
||||||
|
appendChatLog(`connect failed: ${String(error)}`);
|
||||||
|
signallingClient = null;
|
||||||
|
setChatConnected(false);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
chatDisconnectBtn.addEventListener("click", () => {
|
||||||
|
if (signallingClient === null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
signallingClient.disconnect();
|
||||||
|
signallingClient = null;
|
||||||
|
setChatConnected(false);
|
||||||
|
updatePeerList([]);
|
||||||
|
});
|
||||||
|
|
||||||
|
chatSendBtn.addEventListener("click", () => {
|
||||||
|
if (signallingClient === null) {
|
||||||
|
appendChatLog("not connected");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const text = chatInput.value.trim();
|
||||||
|
if (text.length === 0) {
|
||||||
|
appendChatLog("chat message is empty");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
signallingClient.sendChat(text);
|
||||||
|
chatInput.value = "";
|
||||||
|
});
|
||||||
|
|
||||||
|
setChatConnected(false);
|
||||||
|
|
||||||
|
|||||||
@@ -71,3 +71,19 @@ pre {
|
|||||||
padding: 12px;
|
padding: 12px;
|
||||||
white-space: pre-wrap;
|
white-space: pre-wrap;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.chat-grid {
|
||||||
|
display: grid;
|
||||||
|
grid-template-columns: 1fr 1fr;
|
||||||
|
gap: 16px;
|
||||||
|
margin-bottom: 16px;
|
||||||
|
}
|
||||||
|
|
||||||
|
input[type="text"] {
|
||||||
|
border: 1px solid #374151;
|
||||||
|
border-radius: 8px;
|
||||||
|
padding: 10px 12px;
|
||||||
|
background: #0b1220;
|
||||||
|
color: #f9fafb;
|
||||||
|
min-width: 220px;
|
||||||
|
}
|
||||||
|
|||||||
3
frontend/ts/bindings/ClientWsMessage.ts
Normal file
3
frontend/ts/bindings/ClientWsMessage.ts
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
// This file was generated by [ts-rs](https://github.com/Aleph-Alpha/ts-rs). Do not edit this file manually.
|
||||||
|
|
||||||
|
export type ClientWsMessage = { "type": "hello", display_name: string, } | { "type": "chat_send", text: string, } | { "type": "offer", target_peer_id: string, sdp: string, } | { "type": "answer", target_peer_id: string, sdp: string, } | { "type": "ice_candidate", target_peer_id: string, candidate: string, sdp_mid: string | null, sdp_mline_index: number | null, } | { "type": "ping" };
|
||||||
3
frontend/ts/bindings/PeerInfo.ts
Normal file
3
frontend/ts/bindings/PeerInfo.ts
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
// This file was generated by [ts-rs](https://github.com/Aleph-Alpha/ts-rs). Do not edit this file manually.
|
||||||
|
|
||||||
|
export type PeerInfo = { peer_id: string, display_name: string, };
|
||||||
4
frontend/ts/bindings/ServerWsMessage.ts
Normal file
4
frontend/ts/bindings/ServerWsMessage.ts
Normal file
@@ -0,0 +1,4 @@
|
|||||||
|
// This file was generated by [ts-rs](https://github.com/Aleph-Alpha/ts-rs). Do not edit this file manually.
|
||||||
|
import type { PeerInfo } from "./PeerInfo";
|
||||||
|
|
||||||
|
export type ServerWsMessage = { "type": "welcome", peer_id: string, } | { "type": "peer_list", peers: Array<PeerInfo>, } | { "type": "peer_joined", peer: PeerInfo, } | { "type": "peer_left", peer_id: string, } | { "type": "chat_receive", from_peer_id: string, from_display_name: string, text: string, } | { "type": "offer", from_peer_id: string, sdp: string, } | { "type": "answer", from_peer_id: string, sdp: string, } | { "type": "ice_candidate", from_peer_id: string, candidate: string, sdp_mid: string | null, sdp_mline_index: number | null, } | { "type": "pong" } | { "type": "error", message: string, };
|
||||||
@@ -1,7 +1,7 @@
|
|||||||
{
|
{
|
||||||
"name": "tauri-video03",
|
"name": "tauri-video03",
|
||||||
"private": true,
|
"private": true,
|
||||||
"version": "0.1.0",
|
"version": "0.1.1",
|
||||||
"type": "module",
|
"type": "module",
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"dev": "vite",
|
"dev": "vite",
|
||||||
@@ -11,7 +11,8 @@
|
|||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@tauri-apps/api": "^2.10",
|
"@tauri-apps/api": "^2.10",
|
||||||
"@tauri-apps/plugin-opener": "^2.5"
|
"@tauri-apps/plugin-opener": "^2.5",
|
||||||
|
"@tauri-apps/plugin-websocket": "^2.4"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@tauri-apps/cli": "^2.10",
|
"@tauri-apps/cli": "^2.10",
|
||||||
|
|||||||
@@ -33,6 +33,7 @@ pub fn run() {
|
|||||||
init_gstreamer();
|
init_gstreamer();
|
||||||
|
|
||||||
let builder = tauri::Builder::default()
|
let builder = tauri::Builder::default()
|
||||||
|
.plugin(tauri_plugin_websocket::init())
|
||||||
.plugin(tauri_plugin_opener::init())
|
.plugin(tauri_plugin_opener::init())
|
||||||
.manage(app_state::AppState::new())
|
.manage(app_state::AppState::new())
|
||||||
.invoke_handler(tauri::generate_handler![
|
.invoke_handler(tauri::generate_handler![
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
{
|
{
|
||||||
"$schema": "https://schema.tauri.app/config/2",
|
"$schema": "https://schema.tauri.app/config/2",
|
||||||
"productName": "tauri-video03",
|
"productName": "tauri-video03",
|
||||||
"version": "0.1.0",
|
"version": "0.1.1",
|
||||||
"identifier": "com.sinus.tauri-video03",
|
"identifier": "com.sinus.tauri-video03",
|
||||||
"build": {
|
"build": {
|
||||||
"beforeDevCommand": "npm run dev",
|
"beforeDevCommand": "npm run dev",
|
||||||
|
|||||||
@@ -7,6 +7,7 @@ const host = process.env.TAURI_DEV_HOST;
|
|||||||
// https://vite.dev/config/
|
// https://vite.dev/config/
|
||||||
export default defineConfig(async () => ({
|
export default defineConfig(async () => ({
|
||||||
|
|
||||||
|
envPrefix: ['VITE_', 'TAURI_ENV_*'],
|
||||||
// Vite options tailored for Tauri development and only applied in `tauri dev` or `tauri build`
|
// Vite options tailored for Tauri development and only applied in `tauri dev` or `tauri build`
|
||||||
//
|
//
|
||||||
// 1. prevent Vite from obscuring rust errors
|
// 1. prevent Vite from obscuring rust errors
|
||||||
@@ -61,7 +62,7 @@ export default defineConfig(async () => ({
|
|||||||
// 2. tauri expects a fixed port, fail if that port is not available
|
// 2. tauri expects a fixed port, fail if that port is not available
|
||||||
server: {
|
server: {
|
||||||
port: 1420,
|
port: 1420,
|
||||||
strictPort: true,
|
strictPort: false,
|
||||||
host: host || false,
|
host: host || false,
|
||||||
hmr: host
|
hmr: host
|
||||||
? {
|
? {
|
||||||
|
|||||||
Reference in New Issue
Block a user