Runpod support
This commit is contained in:
+7
-1
@@ -297,6 +297,11 @@ async def update_worker_endpoint(request):
|
||||
worker.pop("extra_args", None)
|
||||
else:
|
||||
worker["extra_args"] = data["extra_args"]
|
||||
|
||||
# Handle type field
|
||||
if "type" in data:
|
||||
worker["type"] = data["type"]
|
||||
|
||||
worker_found = True
|
||||
break
|
||||
|
||||
@@ -310,7 +315,8 @@ async def update_worker_endpoint(request):
|
||||
"port": data["port"],
|
||||
"cuda_device": data["cuda_device"],
|
||||
"enabled": data.get("enabled", False),
|
||||
"extra_args": data.get("extra_args", "")
|
||||
"extra_args": data.get("extra_args", ""),
|
||||
"type": data.get("type", "local")
|
||||
}
|
||||
if "workers" not in config:
|
||||
config["workers"] = []
|
||||
|
||||
+23
-6
@@ -266,13 +266,17 @@ class DistributedExtension {
|
||||
getWorkerUrl(worker, endpoint = '') {
|
||||
const host = worker.host || window.location.hostname;
|
||||
|
||||
// Simple rule: port 443 = HTTPS, anything else = HTTP
|
||||
const useHttps = worker.port === 443;
|
||||
// Cloud workers always use HTTPS
|
||||
const isCloud = worker.type === 'cloud';
|
||||
// Simple rule: port 443 = HTTPS, cloud workers = HTTPS, anything else = HTTP
|
||||
const useHttps = isCloud || worker.port === 443;
|
||||
const protocol = useHttps ? 'https' : 'http';
|
||||
|
||||
// Cloud workers use default HTTPS port (443)
|
||||
const effectivePort = isCloud ? 443 : worker.port;
|
||||
// Don't add port for standard HTTPS/HTTP ports
|
||||
const defaultPort = useHttps ? 443 : 80;
|
||||
const port = worker.port === defaultPort ? '' : `:${worker.port}`;
|
||||
const port = effectivePort === defaultPort ? '' : `:${effectivePort}`;
|
||||
|
||||
return `${protocol}://${host}${port}${endpoint}`;
|
||||
}
|
||||
@@ -695,10 +699,19 @@ class DistributedExtension {
|
||||
}
|
||||
|
||||
isRemoteWorker(worker) {
|
||||
// Check if explicitly marked as cloud worker
|
||||
if (worker.type === "cloud") {
|
||||
return true;
|
||||
}
|
||||
// Otherwise check by host (backward compatibility)
|
||||
const host = worker.host || window.location.hostname;
|
||||
return host !== "localhost" && host !== "127.0.0.1" && host !== window.location.hostname;
|
||||
}
|
||||
|
||||
isCloudWorker(worker) {
|
||||
return worker.type === "cloud";
|
||||
}
|
||||
|
||||
getMasterUrl() {
|
||||
// Always use the detected/configured master IP for consistency
|
||||
if (this.config?.master?.host) {
|
||||
@@ -873,7 +886,9 @@ class DistributedExtension {
|
||||
|
||||
// Get form values
|
||||
const name = document.getElementById(`name-${workerId}`).value;
|
||||
const isRemote = document.getElementById(`remote-${workerId}`).checked;
|
||||
const workerType = document.getElementById(`worker-type-${workerId}`).value;
|
||||
const isRemote = workerType === 'remote' || workerType === 'cloud';
|
||||
const isCloud = workerType === 'cloud';
|
||||
const host = isRemote ? document.getElementById(`host-${workerId}`).value : window.location.hostname;
|
||||
const port = parseInt(document.getElementById(`port-${workerId}`).value);
|
||||
const cudaDevice = isRemote ? undefined : parseInt(document.getElementById(`cuda-${workerId}`).value);
|
||||
@@ -890,7 +905,7 @@ class DistributedExtension {
|
||||
return;
|
||||
}
|
||||
|
||||
if (isRemote && !host.trim()) {
|
||||
if ((workerType === 'remote' || workerType === 'cloud') && !host.trim()) {
|
||||
app.extensionManager.toast.add({
|
||||
severity: "error",
|
||||
summary: "Validation Error",
|
||||
@@ -900,7 +915,7 @@ class DistributedExtension {
|
||||
return;
|
||||
}
|
||||
|
||||
if (isNaN(port) || port < 1 || port > 65535) {
|
||||
if (!isCloud && (isNaN(port) || port < 1 || port > 65535)) {
|
||||
app.extensionManager.toast.add({
|
||||
severity: "error",
|
||||
summary: "Validation Error",
|
||||
@@ -963,6 +978,7 @@ class DistributedExtension {
|
||||
try {
|
||||
await this.api.updateWorker(workerId, {
|
||||
name: name.trim(),
|
||||
type: workerType,
|
||||
host: isRemote ? host.trim() : null,
|
||||
port: port,
|
||||
cuda_device: isRemote ? null : cudaDevice,
|
||||
@@ -971,6 +987,7 @@ class DistributedExtension {
|
||||
|
||||
// Update local config
|
||||
worker.name = name.trim();
|
||||
worker.type = workerType;
|
||||
if (isRemote) {
|
||||
worker.host = host.trim();
|
||||
delete worker.cuda_device;
|
||||
|
||||
@@ -49,7 +49,12 @@ const cardConfigs = {
|
||||
},
|
||||
infoText: (data, extension) => {
|
||||
const isRemote = extension.isRemoteWorker(data);
|
||||
if (isRemote) {
|
||||
const isCloud = data.type === 'cloud';
|
||||
|
||||
if (isCloud) {
|
||||
// For cloud workers, don't show port (it's always 443)
|
||||
return `<strong>${data.name}</strong><br><small style="color: ${UI_COLORS.MUTED_TEXT};">${data.host}</small>`;
|
||||
} else if (isRemote) {
|
||||
return `<strong>${data.name}</strong><br><small style="color: ${UI_COLORS.MUTED_TEXT};">${data.host}:${data.port}</small>`;
|
||||
} else {
|
||||
const cudaInfo = data.cuda_device !== undefined ? `CUDA ${data.cuda_device} • ` : '';
|
||||
@@ -525,66 +530,130 @@ export class DistributedUI {
|
||||
const nameGroup = this.createFormGroup("Name:", worker.name, `name-${worker.id}`);
|
||||
form.appendChild(nameGroup.group);
|
||||
|
||||
// Remote checkbox
|
||||
const remoteGroup = document.createElement("div");
|
||||
remoteGroup.style.cssText = "display: flex; align-items: center; gap: 8px; margin: 5px 0;";
|
||||
// Worker type dropdown
|
||||
const typeGroup = document.createElement("div");
|
||||
typeGroup.style.cssText = "display: flex; flex-direction: column; gap: 4px; margin: 5px 0;";
|
||||
|
||||
const remoteCheckbox = document.createElement("input");
|
||||
remoteCheckbox.type = "checkbox";
|
||||
remoteCheckbox.id = `remote-${worker.id}`;
|
||||
remoteCheckbox.checked = extension.isRemoteWorker(worker);
|
||||
remoteCheckbox.onchange = (e) => {
|
||||
const isRemote = e.target.checked;
|
||||
const typeLabel = document.createElement("label");
|
||||
typeLabel.htmlFor = `worker-type-${worker.id}`;
|
||||
typeLabel.textContent = "Worker Type:";
|
||||
typeLabel.style.cssText = "font-size: 12px; color: #ccc;";
|
||||
|
||||
const typeSelect = document.createElement("select");
|
||||
typeSelect.id = `worker-type-${worker.id}`;
|
||||
typeSelect.style.cssText = "padding: 4px 8px; background: #333; color: #fff; border: 1px solid #555; border-radius: 4px; font-size: 12px;";
|
||||
|
||||
// Create options
|
||||
const localOption = document.createElement("option");
|
||||
localOption.value = "local";
|
||||
localOption.textContent = "Local";
|
||||
|
||||
const remoteOption = document.createElement("option");
|
||||
remoteOption.value = "remote";
|
||||
remoteOption.textContent = "Remote";
|
||||
|
||||
const cloudOption = document.createElement("option");
|
||||
cloudOption.value = "cloud";
|
||||
cloudOption.textContent = "Cloud";
|
||||
|
||||
typeSelect.appendChild(localOption);
|
||||
typeSelect.appendChild(remoteOption);
|
||||
typeSelect.appendChild(cloudOption);
|
||||
|
||||
// Create powered by Runpod text (initially hidden)
|
||||
const runpodText = document.createElement("a");
|
||||
runpodText.id = `runpod-text-${worker.id}`;
|
||||
runpodText.href = "https://www.runpod.io";
|
||||
runpodText.target = "_blank";
|
||||
runpodText.textContent = "Deploy cloud worker with Runpod";
|
||||
runpodText.style.cssText = "font-size: 12px; color: #4a90e2; text-decoration: none; margin-top: 4px; display: none; cursor: pointer;";
|
||||
|
||||
typeSelect.onchange = (e) => {
|
||||
const workerType = e.target.value;
|
||||
// Show/hide relevant fields
|
||||
const hostGroup = document.getElementById(`host-group-${worker.id}`);
|
||||
const hostInput = document.getElementById(`host-${worker.id}`);
|
||||
const portGroup = document.getElementById(`port-group-${worker.id}`);
|
||||
const portInput = document.getElementById(`port-${worker.id}`);
|
||||
const cudaGroup = document.getElementById(`cuda-group-${worker.id}`);
|
||||
const argsGroup = document.getElementById(`args-group-${worker.id}`);
|
||||
const runpodTextElem = document.getElementById(`runpod-text-${worker.id}`);
|
||||
|
||||
if (isRemote) {
|
||||
if (workerType === "local") {
|
||||
hostGroup.style.display = "none";
|
||||
portGroup.style.display = "flex";
|
||||
cudaGroup.style.display = "flex";
|
||||
argsGroup.style.display = "flex";
|
||||
runpodTextElem.style.display = "none";
|
||||
} else if (workerType === "remote") {
|
||||
hostGroup.style.display = "flex";
|
||||
portGroup.style.display = "flex";
|
||||
cudaGroup.style.display = "none";
|
||||
argsGroup.style.display = "none";
|
||||
runpodTextElem.style.display = "none";
|
||||
// Update placeholder for remote workers
|
||||
hostInput.placeholder = "e.g., 192.168.1.100";
|
||||
// If switching to remote and host is localhost, clear it
|
||||
const hostInput = document.getElementById(`host-${worker.id}`);
|
||||
if (hostInput.value === "localhost" || hostInput.value === "127.0.0.1") {
|
||||
hostInput.value = "";
|
||||
}
|
||||
} else {
|
||||
hostGroup.style.display = "none";
|
||||
cudaGroup.style.display = "flex";
|
||||
argsGroup.style.display = "flex";
|
||||
} else if (workerType === "cloud") {
|
||||
hostGroup.style.display = "flex";
|
||||
portGroup.style.display = "flex"; // Keep port visible for cloud workers
|
||||
cudaGroup.style.display = "none";
|
||||
argsGroup.style.display = "none";
|
||||
runpodTextElem.style.display = "block";
|
||||
// Update placeholder for cloud workers
|
||||
hostInput.placeholder = "e.g., your-cloud-worker.trycloudflare.com";
|
||||
// Set port to 443 for cloud workers
|
||||
portInput.value = "443";
|
||||
// If switching to cloud and host is localhost, clear it
|
||||
if (hostInput.value === "localhost" || hostInput.value === "127.0.0.1") {
|
||||
hostInput.value = "";
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
const remoteLabel = document.createElement("label");
|
||||
remoteLabel.htmlFor = `remote-${worker.id}`;
|
||||
remoteLabel.textContent = "Remote Worker";
|
||||
remoteLabel.style.cssText = "font-size: 12px; color: #ccc; cursor: pointer;";
|
||||
typeGroup.appendChild(typeLabel);
|
||||
typeGroup.appendChild(typeSelect);
|
||||
typeGroup.appendChild(runpodText);
|
||||
form.appendChild(typeGroup);
|
||||
|
||||
remoteGroup.appendChild(remoteCheckbox);
|
||||
remoteGroup.appendChild(remoteLabel);
|
||||
form.appendChild(remoteGroup);
|
||||
// Set initial value based on worker type
|
||||
if (worker.type === "cloud") {
|
||||
typeSelect.value = "cloud";
|
||||
// Show Runpod text immediately for cloud workers
|
||||
runpodText.style.display = "block";
|
||||
} else if (extension.isRemoteWorker(worker)) {
|
||||
typeSelect.value = "remote";
|
||||
} else {
|
||||
typeSelect.value = "local";
|
||||
}
|
||||
|
||||
// Trigger initial state
|
||||
typeSelect.dispatchEvent(new Event('change'));
|
||||
|
||||
// Host field (only for remote workers)
|
||||
const hostGroup = this.createFormGroup("Host:", worker.host || "", `host-${worker.id}`, "text", "e.g., 192.168.1.100");
|
||||
hostGroup.group.id = `host-group-${worker.id}`;
|
||||
hostGroup.group.style.display = extension.isRemoteWorker(worker) ? "flex" : "none";
|
||||
hostGroup.group.style.display = (extension.isRemoteWorker(worker) || worker.type === "cloud") ? "flex" : "none";
|
||||
form.appendChild(hostGroup.group);
|
||||
|
||||
// Port field
|
||||
const portGroup = this.createFormGroup("Port:", worker.port, `port-${worker.id}`, "number");
|
||||
portGroup.group.id = `port-group-${worker.id}`;
|
||||
form.appendChild(portGroup.group);
|
||||
|
||||
// CUDA Device field (only for local workers)
|
||||
const cudaGroup = this.createFormGroup("CUDA Device:", worker.cuda_device || 0, `cuda-${worker.id}`, "number");
|
||||
cudaGroup.group.id = `cuda-group-${worker.id}`;
|
||||
cudaGroup.group.style.display = extension.isRemoteWorker(worker) ? "none" : "flex";
|
||||
cudaGroup.group.style.display = (extension.isRemoteWorker(worker) || worker.type === "cloud") ? "none" : "flex";
|
||||
form.appendChild(cudaGroup.group);
|
||||
|
||||
// Extra Args field (only for local workers)
|
||||
const argsGroup = this.createFormGroup("Extra Args:", worker.extra_args || "", `args-${worker.id}`);
|
||||
argsGroup.group.id = `args-group-${worker.id}`;
|
||||
argsGroup.group.style.display = extension.isRemoteWorker(worker) ? "none" : "flex";
|
||||
argsGroup.group.style.display = (extension.isRemoteWorker(worker) || worker.type === "cloud") ? "none" : "flex";
|
||||
form.appendChild(argsGroup.group);
|
||||
|
||||
// Buttons
|
||||
@@ -728,7 +797,9 @@ export class DistributedUI {
|
||||
|
||||
if (config.dynamic && data) {
|
||||
if (isRemote) {
|
||||
const remoteInfo = this.createButton("Remote worker", null, BUTTON_STYLES.info);
|
||||
const isCloud = data.type === 'cloud';
|
||||
const workerTypeText = isCloud ? "Cloud worker" : "Remote worker";
|
||||
const remoteInfo = this.createButton(workerTypeText, null, BUTTON_STYLES.info);
|
||||
remoteInfo.style.cssText = BUTTON_STYLES.base + BUTTON_STYLES.workerControl + BUTTON_STYLES.info + " color: #999; cursor: default;";
|
||||
remoteInfo.disabled = true;
|
||||
controlsWrapper.appendChild(remoteInfo);
|
||||
|
||||
Reference in New Issue
Block a user