Svelte: Restore support for Tailscale connection
This commit is contained in:
parent
de34cb587e
commit
f4648b08e6
4 changed files with 145 additions and 8 deletions
|
@ -1,11 +1,102 @@
|
||||||
<script>
|
<script>
|
||||||
var currentIp = null;
|
import { networkData, startLogin } from '$lib/network.js'
|
||||||
|
import { createEventDispatcher } from 'svelte';
|
||||||
|
var dispatch = createEventDispatcher();
|
||||||
|
var connectionState = networkData.connectionState;
|
||||||
|
function handleConnect() {
|
||||||
|
connectionState.set("DOWNLOADING");
|
||||||
|
dispatch('connect');
|
||||||
|
}
|
||||||
|
async function handleCopyIP(event)
|
||||||
|
{
|
||||||
|
// To prevent the default contexmenu from showing up when right-clicking..
|
||||||
|
event.preventDefault();
|
||||||
|
// Copy the IP to the clipboard.
|
||||||
|
try
|
||||||
|
{
|
||||||
|
await window.navigator.clipboard.writeText(networkData.currentIp)
|
||||||
|
connectionState.set("IPCOPIED");
|
||||||
|
setTimeout(() => {
|
||||||
|
connectionState.set("CONNECTED");
|
||||||
|
}, 2000);
|
||||||
|
}
|
||||||
|
catch(msg)
|
||||||
|
{
|
||||||
|
console.log("Copy ip to clipboard: Error: " + msg);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
function getButtonText(state)
|
||||||
|
{
|
||||||
|
switch(state)
|
||||||
|
{
|
||||||
|
case "DISCONNECTED":
|
||||||
|
return "Connect to Tailscale";
|
||||||
|
case "DOWNLOADING":
|
||||||
|
return "Loading IP stack...";
|
||||||
|
case "LOGINSTARTING":
|
||||||
|
return "Starting Login...";
|
||||||
|
case "LOGINREADY":
|
||||||
|
return "Login to Tailscale";
|
||||||
|
case "CONNECTED":
|
||||||
|
return `IP: ${networkData.currentIp}`;
|
||||||
|
case "IPCOPIED":
|
||||||
|
return "Copied!";
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
return `Text for state: ${state}`;
|
||||||
|
}
|
||||||
|
function isClickableState(state)
|
||||||
|
{
|
||||||
|
switch(state)
|
||||||
|
{
|
||||||
|
case "DISCONNECTED":
|
||||||
|
case "LOGINREADY":
|
||||||
|
case "CONNECTED":
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
function getClickHandler(state)
|
||||||
|
{
|
||||||
|
switch(state)
|
||||||
|
{
|
||||||
|
case "DISCONNECTED":
|
||||||
|
return handleConnect;
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
function getClickUrl(state)
|
||||||
|
{
|
||||||
|
switch(state)
|
||||||
|
{
|
||||||
|
case "LOGINREADY":
|
||||||
|
return networkData.loginUrl;
|
||||||
|
case "CONNECTED":
|
||||||
|
return networkData.dashboardUrl;
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
function getButtonTooltip(state)
|
||||||
|
{
|
||||||
|
switch(state)
|
||||||
|
{
|
||||||
|
case "CONNECTED":
|
||||||
|
return "Right-click to copy";
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
function getRightClickHandler(state)
|
||||||
|
{
|
||||||
|
switch(state)
|
||||||
|
{
|
||||||
|
case "CONNECTED":
|
||||||
|
return handleCopyIP;
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
</script>
|
</script>
|
||||||
<h1 class="text-lg font-bold">Networking</h1>
|
<h1 class="text-lg font-bold">Networking</h1>
|
||||||
{#if currentIp === null}
|
<a href={getClickUrl($connectionState)} target="_blank" on:click={getClickHandler($connectionState)} on:contextmenu={getRightClickHandler($connectionState)}><p class="bg-neutral-700 p-2 rounded-md {isClickableState($connectionState) ? "hover:bg-neutral-500 cursor-pointer" : ""}" title={getButtonTooltip($connectionState)}><img src="assets/tailscale.svg" class="inline w-8"/><span class="ml-1">{getButtonText($connectionState)}</span></p></a>
|
||||||
<p class="bg-neutral-700 hover:bg-neutral-500 p-2 rounded-md cursor-pointer"><img src="assets/tailscale.svg" class="inline w-8"/><span class="ml-1">Connect to Tailscale</span></p>
|
|
||||||
{:else}
|
|
||||||
<p>Current IP: {currentIp}</p>
|
|
||||||
{/if}
|
|
||||||
<p>WebVM can connect to the Internet via Tailscale</p>
|
<p>WebVM can connect to the Internet via Tailscale</p>
|
||||||
<p>Using Tailscale is required since browser do not support TCP/UDP sockets (yet!)</p>
|
<p>Using Tailscale is required since browser do not support TCP/UDP sockets (yet!)</p>
|
||||||
|
|
|
@ -40,7 +40,7 @@
|
||||||
</div>
|
</div>
|
||||||
<div class="flex flex-col gap-5 shrink-0 w-60 h-full z-10 p-2 bg-neutral-600 text-gray-100" class:hidden={!activeInfo}>
|
<div class="flex flex-col gap-5 shrink-0 w-60 h-full z-10 p-2 bg-neutral-600 text-gray-100" class:hidden={!activeInfo}>
|
||||||
{#if activeInfo === 'Networking'}
|
{#if activeInfo === 'Networking'}
|
||||||
<NetworkingTab />
|
<NetworkingTab on:connect/>
|
||||||
{:else}
|
{:else}
|
||||||
<p>{activeInfo}</p>
|
<p>{activeInfo}</p>
|
||||||
{/if}
|
{/if}
|
||||||
|
|
46
src/lib/network.js
Normal file
46
src/lib/network.js
Normal file
|
@ -0,0 +1,46 @@
|
||||||
|
import { writable } from 'svelte/store';
|
||||||
|
|
||||||
|
let params = new URLSearchParams("?"+window.location.hash.substr(1));
|
||||||
|
let authKey = params.get("authKey") || undefined;
|
||||||
|
let controlUrl = params.get("controlUrl") || undefined;
|
||||||
|
let dashboardUrl = controlUrl ? null : "https://login.tailscale.com/admin/machines";
|
||||||
|
let resolveLogin = null;
|
||||||
|
let loginPromise = new Promise((f,r) => {
|
||||||
|
resolveLogin = f;
|
||||||
|
});
|
||||||
|
let connectionState = writable("DISCONNECTED");
|
||||||
|
|
||||||
|
function loginUrlCb(url)
|
||||||
|
{
|
||||||
|
resolveLogin(url);
|
||||||
|
}
|
||||||
|
|
||||||
|
function stateUpdateCb(state)
|
||||||
|
{
|
||||||
|
switch(state)
|
||||||
|
{
|
||||||
|
case 6 /*Running*/:
|
||||||
|
{
|
||||||
|
connectionState.set("CONNECTED");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function netmapUpdateCb(map)
|
||||||
|
{
|
||||||
|
networkData.currentIp = map.self.addresses[0];
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function startLogin()
|
||||||
|
{
|
||||||
|
connectionState.set("LOGINSTARTING");
|
||||||
|
const url = await loginPromise;
|
||||||
|
networkData.loginUrl = url;
|
||||||
|
connectionState.set("LOGINREADY");
|
||||||
|
return url;
|
||||||
|
}
|
||||||
|
|
||||||
|
export const networkInterface = { authKey: authKey, controlUrl: controlUrl, loginUrlCb: loginUrlCb, stateUpdateCb: stateUpdateCb, netmapUpdateCb: netmapUpdateCb };
|
||||||
|
|
||||||
|
export const networkData = { currentIp: null, connectionState: connectionState, loginUrl: null, dashboardUrl: dashboardUrl }
|
|
@ -17,8 +17,8 @@ export default defineConfig({
|
||||||
targets: [
|
targets: [
|
||||||
{ src: 'tower.ico', dest: '' },
|
{ src: 'tower.ico', dest: '' },
|
||||||
{ src: 'scrollbar.css', dest: '' },
|
{ src: 'scrollbar.css', dest: '' },
|
||||||
{ src: 'network.js', dest: '' },
|
|
||||||
{ src: 'serviceWorker.js', dest: '' },
|
{ src: 'serviceWorker.js', dest: '' },
|
||||||
|
{ src: 'login.html', dest: '' },
|
||||||
{ src: 'assets/', dest: '' }
|
{ src: 'assets/', dest: '' }
|
||||||
]
|
]
|
||||||
})
|
})
|
||||||
|
|
Loading…
Reference in a new issue