import { readdirSync } from "node:fs"; import { join } from "node:path"; import { docker } from "@dokploy/server/constants"; import { getServiceContainer } from "@dokploy/server/utils/docker/utils"; import { execAsyncRemote } from "@dokploy/server/utils/process/execAsync"; // import packageInfo from "../../../package.json"; const updateIsAvailable = async () => { try { const service = await getServiceContainer("dokploy"); const localImage = await docker.getImage(getDokployImage()).inspect(); return localImage.Id !== service?.ImageID; } catch (error) { return false; } }; export const getDokployImage = () => { return `dokploy/dokploy:${process.env.RELEASE_TAG || "latest"}`; }; export const pullLatestRelease = async () => { try { const stream = await docker.pull(getDokployImage(), {}); await new Promise((resolve, reject) => { docker.modem.followProgress(stream, (err, res) => err ? reject(err) : resolve(res), ); }); const newUpdateIsAvailable = await updateIsAvailable(); return newUpdateIsAvailable; } catch (error) {} return false; }; export const getDokployVersion = () => { // return packageInfo.version; }; interface TreeDataItem { id: string; name: string; type: "file" | "directory"; children?: TreeDataItem[]; } export const readDirectory = async ( dirPath: string, serverId?: string, ): Promise => { if (serverId) { const { stdout } = await execAsyncRemote( serverId, ` process_items() { local parent_dir="$1" local __resultvar=$2 local items_json="" local first=true for item in "$parent_dir"/*; do [ -e "$item" ] || continue process_item "$item" item_json if [ "$first" = true ]; then first=false items_json="$item_json" else items_json="$items_json,$item_json" fi done eval $__resultvar="'[$items_json]'" } process_item() { local item_path="$1" local __resultvar=$2 local item_name=$(basename "$item_path") local escaped_name=$(echo "$item_name" | sed 's/"/\\"/g') local escaped_path=$(echo "$item_path" | sed 's/"/\\"/g') if [ -d "$item_path" ]; then # Is directory process_items "$item_path" children_json local json='{"id":"'"$escaped_path"'","name":"'"$escaped_name"'","type":"directory","children":'"$children_json"'}' else # Is file local json='{"id":"'"$escaped_path"'","name":"'"$escaped_name"'","type":"file"}' fi eval $__resultvar="'$json'" } root_dir=${dirPath} process_items "$root_dir" json_output echo "$json_output" `, ); const result = JSON.parse(stdout); return result; } const items = readdirSync(dirPath, { withFileTypes: true }); const stack = [dirPath]; const result: TreeDataItem[] = []; const parentMap: Record = {}; while (stack.length > 0) { const currentPath = stack.pop(); if (!currentPath) continue; const items = readdirSync(currentPath, { withFileTypes: true }); const currentDirectoryResult: TreeDataItem[] = []; for (const item of items) { const fullPath = join(currentPath, item.name); if (item.isDirectory()) { stack.push(fullPath); const directoryItem: TreeDataItem = { id: fullPath, name: item.name, type: "directory", children: [], }; currentDirectoryResult.push(directoryItem); parentMap[fullPath] = directoryItem.children as TreeDataItem[]; } else { const fileItem: TreeDataItem = { id: fullPath, name: item.name, type: "file", }; currentDirectoryResult.push(fileItem); } } if (parentMap[currentPath]) { parentMap[currentPath].push(...currentDirectoryResult); } else { result.push(...currentDirectoryResult); } } return result; };