mirror of
https://github.com/easydiffusion/easydiffusion.git
synced 2025-04-10 11:08:20 +02:00
Merge pull request #1313 from JeLuF/cloudflared
Share ED via Cloudflare's ArgoTunnel
This commit is contained in:
commit
4b36ca75cb
@ -23,6 +23,7 @@ modules_to_check = {
|
|||||||
"rich": "12.6.0",
|
"rich": "12.6.0",
|
||||||
"uvicorn": "0.19.0",
|
"uvicorn": "0.19.0",
|
||||||
"fastapi": "0.85.1",
|
"fastapi": "0.85.1",
|
||||||
|
"pycloudflared": "0.2.0",
|
||||||
# "xformers": "0.0.16",
|
# "xformers": "0.0.16",
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -15,6 +15,7 @@ from fastapi import FastAPI, HTTPException
|
|||||||
from fastapi.staticfiles import StaticFiles
|
from fastapi.staticfiles import StaticFiles
|
||||||
from pydantic import BaseModel, Extra
|
from pydantic import BaseModel, Extra
|
||||||
from starlette.responses import FileResponse, JSONResponse, StreamingResponse
|
from starlette.responses import FileResponse, JSONResponse, StreamingResponse
|
||||||
|
from pycloudflared import try_cloudflare
|
||||||
|
|
||||||
log.info(f"started in {app.SD_DIR}")
|
log.info(f"started in {app.SD_DIR}")
|
||||||
log.info(f"started at {datetime.datetime.now():%x %X}")
|
log.info(f"started at {datetime.datetime.now():%x %X}")
|
||||||
@ -113,6 +114,14 @@ def init():
|
|||||||
def get_image(task_id: int, img_id: int):
|
def get_image(task_id: int, img_id: int):
|
||||||
return get_image_internal(task_id, img_id)
|
return get_image_internal(task_id, img_id)
|
||||||
|
|
||||||
|
@server_api.post("/tunnel/cloudflare/start")
|
||||||
|
def start_cloudflare_tunnel(req: dict):
|
||||||
|
return start_cloudflare_tunnel_internal(req)
|
||||||
|
|
||||||
|
@server_api.post("/tunnel/cloudflare/stop")
|
||||||
|
def stop_cloudflare_tunnel(req: dict):
|
||||||
|
return stop_cloudflare_tunnel_internal(req)
|
||||||
|
|
||||||
@server_api.get("/")
|
@server_api.get("/")
|
||||||
def read_root():
|
def read_root():
|
||||||
return FileResponse(os.path.join(app.SD_UI_DIR, "index.html"), headers=NOCACHE_HEADERS)
|
return FileResponse(os.path.join(app.SD_UI_DIR, "index.html"), headers=NOCACHE_HEADERS)
|
||||||
@ -211,6 +220,8 @@ def ping_internal(session_id: str = None):
|
|||||||
session = task_manager.get_cached_session(session_id, update_ttl=True)
|
session = task_manager.get_cached_session(session_id, update_ttl=True)
|
||||||
response["tasks"] = {id(t): t.status for t in session.tasks}
|
response["tasks"] = {id(t): t.status for t in session.tasks}
|
||||||
response["devices"] = task_manager.get_devices()
|
response["devices"] = task_manager.get_devices()
|
||||||
|
if cloudflare.address != None:
|
||||||
|
response["cloudflare"] = cloudflare.address
|
||||||
return JSONResponse(response, headers=NOCACHE_HEADERS)
|
return JSONResponse(response, headers=NOCACHE_HEADERS)
|
||||||
|
|
||||||
|
|
||||||
@ -322,3 +333,46 @@ def get_image_internal(task_id: int, img_id: int):
|
|||||||
return StreamingResponse(img_data, media_type="image/jpeg")
|
return StreamingResponse(img_data, media_type="image/jpeg")
|
||||||
except KeyError as e:
|
except KeyError as e:
|
||||||
raise HTTPException(status_code=500, detail=str(e))
|
raise HTTPException(status_code=500, detail=str(e))
|
||||||
|
|
||||||
|
#---- Cloudflare Tunnel ----
|
||||||
|
class CloudflareTunnel:
|
||||||
|
def __init__(self):
|
||||||
|
config = app.getConfig()
|
||||||
|
self.Urls = None
|
||||||
|
self.port = config["net"]["listen_port"]
|
||||||
|
|
||||||
|
def start(self):
|
||||||
|
self.Urls = try_cloudflare(self.port)
|
||||||
|
|
||||||
|
def stop(self):
|
||||||
|
if self.Urls != None:
|
||||||
|
try_cloudflare.terminate(self.port)
|
||||||
|
self.Urls = None
|
||||||
|
|
||||||
|
@property
|
||||||
|
def address(self):
|
||||||
|
if self.Urls != None:
|
||||||
|
return self.Urls.tunnel
|
||||||
|
else:
|
||||||
|
return None
|
||||||
|
|
||||||
|
cloudflare = CloudflareTunnel()
|
||||||
|
|
||||||
|
def start_cloudflare_tunnel_internal(req: dict):
|
||||||
|
try:
|
||||||
|
cloudflare.start()
|
||||||
|
log.info(f"- Started cloudflare tunnel. Using address: {cloudflare.address}")
|
||||||
|
return JSONResponse({"address":cloudflare.address})
|
||||||
|
except Exception as e:
|
||||||
|
log.error(str(e))
|
||||||
|
log.error(traceback.format_exc())
|
||||||
|
return HTTPException(status_code=500, detail=str(e))
|
||||||
|
|
||||||
|
def stop_cloudflare_tunnel_internal(req: dict):
|
||||||
|
try:
|
||||||
|
cloudflare.stop()
|
||||||
|
except Exception as e:
|
||||||
|
log.error(str(e))
|
||||||
|
log.error(traceback.format_exc())
|
||||||
|
return HTTPException(status_code=500, detail=str(e))
|
||||||
|
|
||||||
|
@ -361,10 +361,16 @@
|
|||||||
<div id="tab-content-settings" class="tab-content">
|
<div id="tab-content-settings" class="tab-content">
|
||||||
<div id="system-settings" class="tab-content-inner">
|
<div id="system-settings" class="tab-content-inner">
|
||||||
<h1>System Settings</h1>
|
<h1>System Settings</h1>
|
||||||
<div class="parameters-table"></div>
|
<div class="parameters-table" id="system-settings-table"></div>
|
||||||
<br/>
|
<br/>
|
||||||
<button id="save-system-settings-btn" class="primaryButton">Save</button>
|
<button id="save-system-settings-btn" class="primaryButton">Save</button>
|
||||||
<br/><br/>
|
<br/><br/>
|
||||||
|
<div id="share-easy-diffusion">
|
||||||
|
<h3><i class="fa fa-user-group"></i> Share Easy Diffusion</h3>
|
||||||
|
<div class="parameters-table" id="system-settings-network-table">
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<br/><br/>
|
||||||
<div>
|
<div>
|
||||||
<h3><i class="fa fa-microchip icon"></i> System Info</h3>
|
<h3><i class="fa fa-microchip icon"></i> System Info</h3>
|
||||||
<div id="system-info">
|
<div id="system-info">
|
||||||
@ -539,7 +545,8 @@ async function init() {
|
|||||||
SD.init({
|
SD.init({
|
||||||
events: {
|
events: {
|
||||||
statusChange: setServerStatus,
|
statusChange: setServerStatus,
|
||||||
idle: onIdle
|
idle: onIdle,
|
||||||
|
ping: tunnelUpdate
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
|
@ -69,11 +69,13 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
.parameters-table > div:first-child {
|
.parameters-table > div:first-child {
|
||||||
border-radius: 12px 12px 0px 0px;
|
border-top-left-radius: 12px;
|
||||||
|
border-top-right-radius: 12px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.parameters-table > div:last-child {
|
.parameters-table > div:last-child {
|
||||||
border-radius: 0px 0px 12px 12px;
|
border-bottom-left-radius: 12px;
|
||||||
|
border-bottom-right-radius: 12px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.parameters-table .fa-fire {
|
.parameters-table .fa-fire {
|
||||||
|
@ -1309,6 +1309,21 @@ body.wait-pause {
|
|||||||
padding-left: 5pt;
|
padding-left: 5pt;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#cloudflare-address {
|
||||||
|
background-color: var(--background-color3);
|
||||||
|
padding: 6px;
|
||||||
|
border-radius: var(--input-border-radius);
|
||||||
|
border: var(--input-border-size) solid var(--input-border-color);
|
||||||
|
margin-top: 0.2em;
|
||||||
|
margin-bottom: 0.2em;
|
||||||
|
display: inline-block;
|
||||||
|
}
|
||||||
|
|
||||||
|
#copy-cloudflare-address {
|
||||||
|
padding: 4px 8px;
|
||||||
|
margin-left: 0.5em;
|
||||||
|
}
|
||||||
|
|
||||||
/* TOAST NOTIFICATIONS */
|
/* TOAST NOTIFICATIONS */
|
||||||
.toast-notification {
|
.toast-notification {
|
||||||
position: fixed;
|
position: fixed;
|
||||||
|
@ -186,6 +186,7 @@
|
|||||||
const EVENT_TASK_START = "taskStart"
|
const EVENT_TASK_START = "taskStart"
|
||||||
const EVENT_TASK_END = "taskEnd"
|
const EVENT_TASK_END = "taskEnd"
|
||||||
const EVENT_TASK_ERROR = "task_error"
|
const EVENT_TASK_ERROR = "task_error"
|
||||||
|
const EVENT_PING = "ping"
|
||||||
const EVENT_UNEXPECTED_RESPONSE = "unexpectedResponse"
|
const EVENT_UNEXPECTED_RESPONSE = "unexpectedResponse"
|
||||||
const EVENTS_TYPES = [
|
const EVENTS_TYPES = [
|
||||||
EVENT_IDLE,
|
EVENT_IDLE,
|
||||||
@ -196,6 +197,7 @@
|
|||||||
EVENT_TASK_START,
|
EVENT_TASK_START,
|
||||||
EVENT_TASK_END,
|
EVENT_TASK_END,
|
||||||
EVENT_TASK_ERROR,
|
EVENT_TASK_ERROR,
|
||||||
|
EVENT_PING,
|
||||||
|
|
||||||
EVENT_UNEXPECTED_RESPONSE,
|
EVENT_UNEXPECTED_RESPONSE,
|
||||||
]
|
]
|
||||||
@ -240,6 +242,7 @@
|
|||||||
setServerStatus("error", "offline")
|
setServerStatus("error", "offline")
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
// Set status
|
// Set status
|
||||||
switch (serverState.status) {
|
switch (serverState.status) {
|
||||||
case ServerStates.init:
|
case ServerStates.init:
|
||||||
@ -261,6 +264,7 @@
|
|||||||
break
|
break
|
||||||
}
|
}
|
||||||
serverState.time = Date.now()
|
serverState.time = Date.now()
|
||||||
|
await eventSource.fireEvent(EVENT_PING, serverState)
|
||||||
return true
|
return true
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
console.error(e)
|
console.error(e)
|
||||||
|
@ -1979,6 +1979,38 @@ resumeBtn.addEventListener("click", function() {
|
|||||||
document.body.classList.remove("wait-pause")
|
document.body.classList.remove("wait-pause")
|
||||||
})
|
})
|
||||||
|
|
||||||
|
function tunnelUpdate(event) {
|
||||||
|
if ("cloudflare" in event) {
|
||||||
|
document.getElementById('cloudflare-off').classList.add("displayNone")
|
||||||
|
document.getElementById('cloudflare-on').classList.remove("displayNone")
|
||||||
|
cloudflareAddressField.innerHTML = event.cloudflare
|
||||||
|
document.getElementById('toggle-cloudflare-tunnel').innerHTML = "Stop"
|
||||||
|
} else {
|
||||||
|
document.getElementById('cloudflare-on').classList.add("displayNone")
|
||||||
|
document.getElementById('cloudflare-off').classList.remove("displayNone")
|
||||||
|
document.getElementById('toggle-cloudflare-tunnel').innerHTML = "Start"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
document.getElementById('toggle-cloudflare-tunnel').addEventListener("click", async function() {
|
||||||
|
let command = "stop"
|
||||||
|
if (document.getElementById('toggle-cloudflare-tunnel').innerHTML == "Start") {
|
||||||
|
command = "start"
|
||||||
|
}
|
||||||
|
showToast(`Cloudflare tunnel ${command} initiated. Please wait.`)
|
||||||
|
|
||||||
|
let res = await fetch("/tunnel/cloudflare/"+command, {
|
||||||
|
method: "POST",
|
||||||
|
headers: {
|
||||||
|
"Content-Type": "application/json",
|
||||||
|
},
|
||||||
|
body: JSON.stringify({}),
|
||||||
|
})
|
||||||
|
res = await res.json()
|
||||||
|
|
||||||
|
console.log(`Cloudflare tunnel ${command} result:`, res)
|
||||||
|
})
|
||||||
|
|
||||||
/* Pause function */
|
/* Pause function */
|
||||||
document.querySelectorAll(".tab").forEach(linkTabContents)
|
document.querySelectorAll(".tab").forEach(linkTabContents)
|
||||||
|
|
||||||
|
@ -11,6 +11,12 @@ var ParameterType = {
|
|||||||
custom: "custom",
|
custom: "custom",
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Element shortcuts
|
||||||
|
*/
|
||||||
|
let parametersTable = document.querySelector("#system-settings-table")
|
||||||
|
let networkParametersTable = document.querySelector("#system-settings-network-table")
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* JSDoc style
|
* JSDoc style
|
||||||
* @typedef {object} Parameter
|
* @typedef {object} Parameter
|
||||||
@ -186,6 +192,7 @@ var PARAMETERS = [
|
|||||||
icon: "fa-network-wired",
|
icon: "fa-network-wired",
|
||||||
default: true,
|
default: true,
|
||||||
saveInAppConfig: true,
|
saveInAppConfig: true,
|
||||||
|
table: networkParametersTable,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
id: "listen_port",
|
id: "listen_port",
|
||||||
@ -198,6 +205,7 @@ var PARAMETERS = [
|
|||||||
return `<input id="${parameter.id}" name="${parameter.id}" size="6" value="9000" onkeypress="preventNonNumericalInput(event)">`
|
return `<input id="${parameter.id}" name="${parameter.id}" size="6" value="9000" onkeypress="preventNonNumericalInput(event)">`
|
||||||
},
|
},
|
||||||
saveInAppConfig: true,
|
saveInAppConfig: true,
|
||||||
|
table: networkParametersTable,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
id: "use_beta_channel",
|
id: "use_beta_channel",
|
||||||
@ -218,6 +226,21 @@ var PARAMETERS = [
|
|||||||
default: false,
|
default: false,
|
||||||
saveInAppConfig: true,
|
saveInAppConfig: true,
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
id: "cloudflare",
|
||||||
|
type: ParameterType.custom,
|
||||||
|
label: "Cloudflare tunnel",
|
||||||
|
note: `<span id="cloudflare-off">Create a VPN tunnel to share your Easy Diffusion instance with your friends. This will
|
||||||
|
generate a web server address on the public Internet for your Easy Diffusion instance. </span>
|
||||||
|
<div id="cloudflare-on" class="displayNone"><div>This Easy Diffusion server is available on the Internet using the
|
||||||
|
address:</div><div><div id="cloudflare-address"></div><button id="copy-cloudflare-address">Copy</button></div></div>
|
||||||
|
<b>Anyone knowing this address can access your server.</b> The address of your server will change each time
|
||||||
|
you share a session.<br>
|
||||||
|
Uses <a href="https://try.cloudflare.com/" target="_blank">Cloudflare services</a>.`,
|
||||||
|
icon: ["fa-brands", "fa-cloudflare"],
|
||||||
|
render: () => '<button id="toggle-cloudflare-tunnel" class="primaryButton">Start</button>',
|
||||||
|
table: networkParametersTable,
|
||||||
|
}
|
||||||
]
|
]
|
||||||
|
|
||||||
function getParameterSettingsEntry(id) {
|
function getParameterSettingsEntry(id) {
|
||||||
@ -266,7 +289,6 @@ function getParameterElement(parameter) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
let parametersTable = document.querySelector("#system-settings .parameters-table")
|
|
||||||
/**
|
/**
|
||||||
* fill in the system settings popup table
|
* fill in the system settings popup table
|
||||||
* @param {Array<Parameter> | undefined} parameters
|
* @param {Array<Parameter> | undefined} parameters
|
||||||
@ -293,7 +315,10 @@ function initParameters(parameters) {
|
|||||||
noteElements.push(noteElement)
|
noteElements.push(noteElement)
|
||||||
}
|
}
|
||||||
|
|
||||||
const icon = parameter.icon ? [createElement("i", undefined, ["fa", parameter.icon])] : []
|
if (typeof(parameter.icon) == "string") {
|
||||||
|
parameter.icon = [parameter.icon]
|
||||||
|
}
|
||||||
|
const icon = parameter.icon ? [createElement("i", undefined, ["fa", ...parameter.icon])] : []
|
||||||
|
|
||||||
const label = typeof parameter.label === "function" ? parameter.label(parameter) : parameter.label
|
const label = typeof parameter.label === "function" ? parameter.label(parameter) : parameter.label
|
||||||
const labelElement = createElement("label", { for: parameter.id })
|
const labelElement = createElement("label", { for: parameter.id })
|
||||||
@ -313,7 +338,13 @@ function initParameters(parameters) {
|
|||||||
elementWrapper,
|
elementWrapper,
|
||||||
]
|
]
|
||||||
)
|
)
|
||||||
parametersTable.appendChild(newrow)
|
|
||||||
|
let p = parametersTable
|
||||||
|
if (parameter.table) {
|
||||||
|
p = parameter.table
|
||||||
|
}
|
||||||
|
p.appendChild(newrow)
|
||||||
|
|
||||||
parameter.settingsEntry = newrow
|
parameter.settingsEntry = newrow
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
@ -667,8 +698,25 @@ saveSettingsBtn.addEventListener("click", function() {
|
|||||||
})
|
})
|
||||||
|
|
||||||
const savePromise = changeAppConfig(updateAppConfigRequest)
|
const savePromise = changeAppConfig(updateAppConfigRequest)
|
||||||
|
showToast("Settings saved")
|
||||||
saveSettingsBtn.classList.add("active")
|
saveSettingsBtn.classList.add("active")
|
||||||
Promise.all([savePromise, asyncDelay(300)]).then(() => saveSettingsBtn.classList.remove("active"))
|
Promise.all([savePromise, asyncDelay(300)]).then(() => saveSettingsBtn.classList.remove("active"))
|
||||||
})
|
})
|
||||||
|
|
||||||
|
listenToNetworkField.addEventListener("change", debounce( ()=>{
|
||||||
|
saveSettingsBtn.click()
|
||||||
|
}, 1000))
|
||||||
|
|
||||||
|
listenPortField.addEventListener("change", debounce( ()=>{
|
||||||
|
saveSettingsBtn.click()
|
||||||
|
}, 1000))
|
||||||
|
|
||||||
|
let copyCloudflareAddressBtn = document.querySelector("#copy-cloudflare-address")
|
||||||
|
let cloudflareAddressField = document.getElementById("cloudflare-address")
|
||||||
|
|
||||||
|
copyCloudflareAddressBtn.addEventListener("click", (e) => {
|
||||||
|
navigator.clipboard.writeText(cloudflareAddressField.innerHTML)
|
||||||
|
showToast("Copied server address to clipboard")
|
||||||
|
})
|
||||||
|
|
||||||
document.addEventListener("system_info_update", (e) => setDeviceInfo(e.detail))
|
document.addEventListener("system_info_update", (e) => setDeviceInfo(e.detail))
|
||||||
|
Loading…
Reference in New Issue
Block a user