mirror of
https://github.com/easydiffusion/easydiffusion.git
synced 2025-02-22 21:32:03 +01:00
Share ED via Cloudflare's ArgoTunnel
Shares the Easy Diffusion instance via https://try.cloudflare.com/
This commit is contained in:
parent
3d7e16cfd9
commit
2080d6e27b
@ -23,6 +23,7 @@ modules_to_check = {
|
||||
"rich": "12.6.0",
|
||||
"uvicorn": "0.19.0",
|
||||
"fastapi": "0.85.1",
|
||||
"pycloudflared": "0.2.0",
|
||||
# "xformers": "0.0.16",
|
||||
}
|
||||
|
||||
|
@ -15,6 +15,7 @@ from fastapi import FastAPI, HTTPException
|
||||
from fastapi.staticfiles import StaticFiles
|
||||
from pydantic import BaseModel, Extra
|
||||
from starlette.responses import FileResponse, JSONResponse, StreamingResponse
|
||||
from pycloudflared import try_cloudflare
|
||||
|
||||
log.info(f"started in {app.SD_DIR}")
|
||||
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):
|
||||
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("/")
|
||||
def read_root():
|
||||
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)
|
||||
response["tasks"] = {id(t): t.status for t in session.tasks}
|
||||
response["devices"] = task_manager.get_devices()
|
||||
if cloudflare.address != None:
|
||||
response["cloudflare"] = cloudflare.address
|
||||
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")
|
||||
except KeyError as 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))
|
||||
|
||||
|
@ -347,10 +347,16 @@
|
||||
<div id="tab-content-settings" class="tab-content">
|
||||
<div id="system-settings" class="tab-content-inner">
|
||||
<h1>System Settings</h1>
|
||||
<div class="parameters-table"></div>
|
||||
<div class="parameters-table" id="system-settings-table"></div>
|
||||
<br/>
|
||||
<button id="save-system-settings-btn" class="primaryButton">Save</button>
|
||||
<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>
|
||||
<h3><i class="fa fa-microchip icon"></i> System Info</h3>
|
||||
<div id="system-info">
|
||||
@ -525,7 +531,8 @@ async function init() {
|
||||
SD.init({
|
||||
events: {
|
||||
statusChange: setServerStatus,
|
||||
idle: onIdle
|
||||
idle: onIdle,
|
||||
ping: tunnelUpdate
|
||||
}
|
||||
})
|
||||
|
||||
|
@ -69,13 +69,15 @@
|
||||
}
|
||||
|
||||
.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 {
|
||||
border-radius: 0px 0px 12px 12px;
|
||||
border-bottom-left-radius: 12px;
|
||||
border-bottom-right-radius: 12px;
|
||||
}
|
||||
|
||||
.parameters-table .fa-fire {
|
||||
color: #F7630C;
|
||||
}
|
||||
}
|
||||
|
@ -1309,6 +1309,15 @@ body.wait-pause {
|
||||
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;
|
||||
}
|
||||
|
||||
/* TOAST NOTIFICATIONS */
|
||||
.toast-notification {
|
||||
position: fixed;
|
||||
|
@ -186,6 +186,7 @@
|
||||
const EVENT_TASK_START = "taskStart"
|
||||
const EVENT_TASK_END = "taskEnd"
|
||||
const EVENT_TASK_ERROR = "task_error"
|
||||
const EVENT_PING = "ping"
|
||||
const EVENT_UNEXPECTED_RESPONSE = "unexpectedResponse"
|
||||
const EVENTS_TYPES = [
|
||||
EVENT_IDLE,
|
||||
@ -196,6 +197,7 @@
|
||||
EVENT_TASK_START,
|
||||
EVENT_TASK_END,
|
||||
EVENT_TASK_ERROR,
|
||||
EVENT_PING,
|
||||
|
||||
EVENT_UNEXPECTED_RESPONSE,
|
||||
]
|
||||
@ -240,6 +242,7 @@
|
||||
setServerStatus("error", "offline")
|
||||
return false
|
||||
}
|
||||
|
||||
// Set status
|
||||
switch (serverState.status) {
|
||||
case ServerStates.init:
|
||||
@ -261,6 +264,7 @@
|
||||
break
|
||||
}
|
||||
serverState.time = Date.now()
|
||||
await eventSource.fireEvent(EVENT_PING, serverState)
|
||||
return true
|
||||
} catch (e) {
|
||||
console.error(e)
|
||||
|
@ -1951,6 +1951,38 @@ resumeBtn.addEventListener("click", function() {
|
||||
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")
|
||||
document.getElementById('cloudflare-address').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 */
|
||||
document.querySelectorAll(".tab").forEach(linkTabContents)
|
||||
|
||||
|
@ -11,6 +11,12 @@ var ParameterType = {
|
||||
custom: "custom",
|
||||
}
|
||||
|
||||
/**
|
||||
* Element shortcuts
|
||||
*/
|
||||
let parametersTable = document.querySelector("#system-settings-table")
|
||||
let networkParametersTable = document.querySelector("#system-settings-network-table")
|
||||
|
||||
/**
|
||||
* JSDoc style
|
||||
* @typedef {object} Parameter
|
||||
@ -186,6 +192,7 @@ var PARAMETERS = [
|
||||
icon: "fa-network-wired",
|
||||
default: true,
|
||||
saveInAppConfig: true,
|
||||
table: networkParametersTable,
|
||||
},
|
||||
{
|
||||
id: "listen_port",
|
||||
@ -198,6 +205,7 @@ var PARAMETERS = [
|
||||
return `<input id="${parameter.id}" name="${parameter.id}" size="6" value="9000" onkeypress="preventNonNumericalInput(event)">`
|
||||
},
|
||||
saveInAppConfig: true,
|
||||
table: networkParametersTable,
|
||||
},
|
||||
{
|
||||
id: "use_beta_channel",
|
||||
@ -218,6 +226,21 @@ var PARAMETERS = [
|
||||
default: false,
|
||||
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 id="cloudflare-address"></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) {
|
||||
@ -266,7 +289,6 @@ function getParameterElement(parameter) {
|
||||
}
|
||||
}
|
||||
|
||||
let parametersTable = document.querySelector("#system-settings .parameters-table")
|
||||
/**
|
||||
* fill in the system settings popup table
|
||||
* @param {Array<Parameter> | undefined} parameters
|
||||
@ -293,7 +315,10 @@ function initParameters(parameters) {
|
||||
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 labelElement = createElement("label", { for: parameter.id })
|
||||
@ -313,7 +338,13 @@ function initParameters(parameters) {
|
||||
elementWrapper,
|
||||
]
|
||||
)
|
||||
parametersTable.appendChild(newrow)
|
||||
|
||||
let p = parametersTable
|
||||
if (parameter.table) {
|
||||
p = parameter.table
|
||||
}
|
||||
p.appendChild(newrow)
|
||||
|
||||
parameter.settingsEntry = newrow
|
||||
})
|
||||
}
|
||||
@ -665,8 +696,17 @@ saveSettingsBtn.addEventListener("click", function() {
|
||||
})
|
||||
|
||||
const savePromise = changeAppConfig(updateAppConfigRequest)
|
||||
showToast("Settings saved")
|
||||
saveSettingsBtn.classList.add("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))
|
||||
|
||||
document.addEventListener("system_info_update", (e) => setDeviceInfo(e.detail))
|
||||
|
Loading…
Reference in New Issue
Block a user