feat: update Dockerfile and workflow for environment variable support

- Modified the Dockerfile to include ARG and ENV for PUBLIC_CONVEX_URL and PUBLIC_CONVEX_SITE_URL, enhancing configuration flexibility.
- Updated the deploy workflow to pass these environment variables during the build process.
- Adjusted package.json to use bun for script commands and added svelte-adapter-bun for improved Svelte integration.
This commit is contained in:
2025-11-26 15:42:22 -03:00
parent 86ae2a1084
commit be959eb230
7 changed files with 440 additions and 405 deletions

View File

@@ -1,432 +1,432 @@
"use node";
// "use node";
import { action } from "../_generated/server";
import { v } from "convex/values";
import { api, internal } from "../_generated/api";
import { Client } from "ssh2";
import { readFileSync } from "fs";
import { decryptSMTPPasswordNode } from "./utils/nodeCrypto";
// import { action } from "../_generated/server";
// import { v } from "convex/values";
// import { api, internal } from "../_generated/api";
// import { Client } from "ssh2";
// import { readFileSync } from "fs";
// import { decryptSMTPPasswordNode } from "./utils/nodeCrypto";
/**
* Interface para configuração SSH
*/
interface SSHConfig {
host: string;
port: number;
username: string;
password?: string;
keyPath?: string;
}
// /**
// * Interface para configuração SSH
// */
// interface SSHConfig {
// host: string;
// port: number;
// username: string;
// password?: string;
// keyPath?: string;
// }
/**
* Executar comando via SSH
*/
async function executarComandoSSH(
config: SSHConfig,
comando: string
): Promise<{ sucesso: boolean; output: string; erro?: string }> {
return new Promise((resolve) => {
const conn = new Client();
let output = "";
let errorOutput = "";
// /**
// * Executar comando via SSH
// */
// async function executarComandoSSH(
// config: SSHConfig,
// comando: string
// ): Promise<{ sucesso: boolean; output: string; erro?: string }> {
// return new Promise((resolve) => {
// const conn = new Client();
// let output = "";
// let errorOutput = "";
conn.on("ready", () => {
conn.exec(comando, (err, stream) => {
if (err) {
conn.end();
resolve({ sucesso: false, output: "", erro: err.message });
return;
}
// conn.on("ready", () => {
// conn.exec(comando, (err, stream) => {
// if (err) {
// conn.end();
// resolve({ sucesso: false, output: "", erro: err.message });
// return;
// }
stream
.on("close", (code: number | null, signal: string | null) => {
conn.end();
if (code === 0) {
resolve({ sucesso: true, output: output.trim() });
} else {
resolve({
sucesso: false,
output: output.trim(),
erro: `Comando retornou código ${code}${signal ? ` (signal: ${signal})` : ""}. ${errorOutput}`,
});
}
})
.on("data", (data: Buffer) => {
output += data.toString();
})
.stderr.on("data", (data: Buffer) => {
errorOutput += data.toString();
});
});
}).on("error", (err) => {
resolve({ sucesso: false, output: "", erro: err.message });
}).connect({
host: config.host,
port: config.port,
username: config.username,
password: config.password,
privateKey: config.keyPath ? readFileSync(config.keyPath) : undefined,
readyTimeout: 10000,
});
});
}
// stream
// .on("close", (code: number | null, signal: string | null) => {
// conn.end();
// if (code === 0) {
// resolve({ sucesso: true, output: output.trim() });
// } else {
// resolve({
// sucesso: false,
// output: output.trim(),
// erro: `Comando retornou código ${code}${signal ? ` (signal: ${signal})` : ""}. ${errorOutput}`,
// });
// }
// })
// .on("data", (data: Buffer) => {
// output += data.toString();
// })
// .stderr.on("data", (data: Buffer) => {
// errorOutput += data.toString();
// });
// });
// }).on("error", (err) => {
// resolve({ sucesso: false, output: "", erro: err.message });
// }).connect({
// host: config.host,
// port: config.port,
// username: config.username,
// password: config.password,
// privateKey: config.keyPath ? readFileSync(config.keyPath) : undefined,
// readyTimeout: 10000,
// });
// });
// }
/**
* Ler arquivo via SSH
*/
async function lerArquivoSSH(
config: SSHConfig,
caminho: string
): Promise<{ sucesso: boolean; conteudo?: string; erro?: string }> {
const comando = `cat "${caminho}" 2>&1`;
const resultado = await executarComandoSSH(config, comando);
// /**
// * Ler arquivo via SSH
// */
// async function lerArquivoSSH(
// config: SSHConfig,
// caminho: string
// ): Promise<{ sucesso: boolean; conteudo?: string; erro?: string }> {
// const comando = `cat "${caminho}" 2>&1`;
// const resultado = await executarComandoSSH(config, comando);
if (!resultado.sucesso) {
return { sucesso: false, erro: resultado.erro || "Erro ao ler arquivo" };
}
// if (!resultado.sucesso) {
// return { sucesso: false, erro: resultado.erro || "Erro ao ler arquivo" };
// }
return { sucesso: true, conteudo: resultado.output };
}
// return { sucesso: true, conteudo: resultado.output };
// }
/**
* Escrever arquivo via SSH
*/
async function escreverArquivoSSH(
config: SSHConfig,
caminho: string,
conteudo: string
): Promise<{ sucesso: boolean; erro?: string }> {
// Escapar conteúdo para shell
const conteudoEscapado = conteudo
.replace(/\\/g, "\\\\")
.replace(/"/g, '\\"')
.replace(/\$/g, "\\$")
.replace(/`/g, "\\`");
// /**
// * Escrever arquivo via SSH
// */
// async function escreverArquivoSSH(
// config: SSHConfig,
// caminho: string,
// conteudo: string
// ): Promise<{ sucesso: boolean; erro?: string }> {
// // Escapar conteúdo para shell
// const conteudoEscapado = conteudo
// .replace(/\\/g, "\\\\")
// .replace(/"/g, '\\"')
// .replace(/\$/g, "\\$")
// .replace(/`/g, "\\`");
const comando = `cat > "${caminho}" << 'JITSI_CONFIG_EOF'
${conteudo}
JITSI_CONFIG_EOF`;
// const comando = `cat > "${caminho}" << 'JITSI_CONFIG_EOF'
// ${conteudo}
// JITSI_CONFIG_EOF`;
const resultado = await executarComandoSSH(config, comando);
// const resultado = await executarComandoSSH(config, comando);
if (!resultado.sucesso) {
return { sucesso: false, erro: resultado.erro || "Erro ao escrever arquivo" };
}
// if (!resultado.sucesso) {
// return { sucesso: false, erro: resultado.erro || "Erro ao escrever arquivo" };
// }
return { sucesso: true };
}
// return { sucesso: true };
// }
/**
* Aplicar configurações do Jitsi no servidor Docker via SSH
*/
export const aplicarConfiguracaoServidor = action({
args: {
configId: v.id("configuracaoJitsi"),
sshPassword: v.optional(v.string()), // Senha SSH (se não usar chave)
},
returns: v.union(
v.object({
sucesso: v.literal(true),
mensagem: v.string(),
detalhes: v.optional(v.string()),
}),
v.object({ sucesso: v.literal(false), erro: v.string() })
),
handler: async (ctx, args): Promise<
| { sucesso: true; mensagem: string; detalhes?: string }
| { sucesso: false; erro: string }
> => {
try {
// Buscar configuração
const config = await ctx.runQuery(api.configuracaoJitsi.obterConfigJitsi, {});
// /**
// * Aplicar configurações do Jitsi no servidor Docker via SSH
// */
// export const aplicarConfiguracaoServidor = action({
// args: {
// configId: v.id("configuracaoJitsi"),
// sshPassword: v.optional(v.string()), // Senha SSH (se não usar chave)
// },
// returns: v.union(
// v.object({
// sucesso: v.literal(true),
// mensagem: v.string(),
// detalhes: v.optional(v.string()),
// }),
// v.object({ sucesso: v.literal(false), erro: v.string() })
// ),
// handler: async (ctx, args): Promise<
// | { sucesso: true; mensagem: string; detalhes?: string }
// | { sucesso: false; erro: string }
// > => {
// try {
// // Buscar configuração
// const config = await ctx.runQuery(api.configuracaoJitsi.obterConfigJitsi, {});
if (!config || config._id !== args.configId) {
return { sucesso: false as const, erro: "Configuração não encontrada" };
}
// if (!config || config._id !== args.configId) {
// return { sucesso: false as const, erro: "Configuração não encontrada" };
// }
// Verificar se tem configurações SSH
const configFull = await ctx.runQuery(api.configuracaoJitsi.obterConfigJitsiCompleta, {
configId: args.configId,
});
// // Verificar se tem configurações SSH
// const configFull = await ctx.runQuery(api.configuracaoJitsi.obterConfigJitsiCompleta, {
// configId: args.configId,
// });
if (!configFull || !configFull.sshHost) {
return {
sucesso: false as const,
erro: "Configurações SSH não estão definidas. Configure o servidor SSH primeiro.",
};
}
// if (!configFull || !configFull.sshHost) {
// return {
// sucesso: false as const,
// erro: "Configurações SSH não estão definidas. Configure o servidor SSH primeiro.",
// };
// }
// Configurar SSH
let sshPasswordDecrypted: string | undefined = undefined;
// // Configurar SSH
// let sshPasswordDecrypted: string | undefined = undefined;
// Se senha foi fornecida, usar ela. Caso contrário, tentar descriptografar a armazenada
if (args.sshPassword) {
sshPasswordDecrypted = args.sshPassword;
} else if (configFull.sshPasswordHash && configFull.sshPasswordHash !== "********") {
// Tentar descriptografar senha armazenada
try {
sshPasswordDecrypted = await decryptSMTPPasswordNode(configFull.sshPasswordHash);
} catch (error) {
return {
sucesso: false as const,
erro: "Não foi possível descriptografar a senha SSH armazenada. Forneça a senha novamente.",
};
}
}
// // Se senha foi fornecida, usar ela. Caso contrário, tentar descriptografar a armazenada
// if (args.sshPassword) {
// sshPasswordDecrypted = args.sshPassword;
// } else if (configFull.sshPasswordHash && configFull.sshPasswordHash !== "********") {
// // Tentar descriptografar senha armazenada
// try {
// sshPasswordDecrypted = await decryptSMTPPasswordNode(configFull.sshPasswordHash);
// } catch (error) {
// return {
// sucesso: false as const,
// erro: "Não foi possível descriptografar a senha SSH armazenada. Forneça a senha novamente.",
// };
// }
// }
const sshConfig: SSHConfig = {
host: configFull.sshHost,
port: configFull.sshPort || 22,
username: configFull.sshUsername || "",
password: sshPasswordDecrypted,
keyPath: configFull.sshKeyPath || undefined,
};
// const sshConfig: SSHConfig = {
// host: configFull.sshHost,
// port: configFull.sshPort || 22,
// username: configFull.sshUsername || "",
// password: sshPasswordDecrypted,
// keyPath: configFull.sshKeyPath || undefined,
// };
if (!sshConfig.username) {
return { sucesso: false as const, erro: "Usuário SSH não configurado" };
}
// if (!sshConfig.username) {
// return { sucesso: false as const, erro: "Usuário SSH não configurado" };
// }
if (!sshConfig.password && !sshConfig.keyPath) {
return {
sucesso: false as const,
erro: "Senha SSH ou caminho da chave deve ser fornecido",
};
}
// if (!sshConfig.password && !sshConfig.keyPath) {
// return {
// sucesso: false as const,
// erro: "Senha SSH ou caminho da chave deve ser fornecido",
// };
// }
const basePath = configFull.jitsiConfigPath || "~/.jitsi-meet-cfg";
const dockerComposePath = configFull.dockerComposePath || ".";
// const basePath = configFull.jitsiConfigPath || "~/.jitsi-meet-cfg";
// const dockerComposePath = configFull.dockerComposePath || ".";
// Extrair host e porta do domain
const [host, portStr] = configFull.domain.split(":");
const port = portStr ? parseInt(portStr, 10) : configFull.useHttps ? 443 : 80;
const protocol = configFull.useHttps ? "https" : "http";
// // Extrair host e porta do domain
// const [host, portStr] = configFull.domain.split(":");
// const port = portStr ? parseInt(portStr, 10) : configFull.useHttps ? 443 : 80;
// const protocol = configFull.useHttps ? "https" : "http";
const detalhes: string[] = [];
// const detalhes: string[] = [];
// 1. Atualizar arquivo .env do docker-compose
if (dockerComposePath) {
const envContent = `# Configuração Jitsi - Atualizada automaticamente pelo SGSE
CONFIG=${basePath}
TZ=America/Recife
ENABLE_LETSENCRYPT=0
HTTP_PORT=${protocol === "https" ? 8000 : port}
HTTPS_PORT=${configFull.useHttps ? port : 8443}
PUBLIC_URL=${protocol}://${host}${portStr ? `:${port}` : ""}
DOMAIN=${host}
ENABLE_AUTH=0
ENABLE_GUESTS=1
ENABLE_TRANSCRIPTION=0
ENABLE_RECORDING=0
ENABLE_PREJOIN_PAGE=0
START_AUDIO_MUTED=0
START_VIDEO_MUTED=0
ENABLE_XMPP_WEBSOCKET=0
ENABLE_P2P=1
MAX_NUMBER_OF_PARTICIPANTS=10
RESOLUTION_WIDTH=1280
RESOLUTION_HEIGHT=720
JWT_APP_ID=${configFull.appId}
JWT_APP_SECRET=
`;
// // 1. Atualizar arquivo .env do docker-compose
// if (dockerComposePath) {
// const envContent = `# Configuração Jitsi - Atualizada automaticamente pelo SGSE
// CONFIG=${basePath}
// TZ=America/Recife
// ENABLE_LETSENCRYPT=0
// HTTP_PORT=${protocol === "https" ? 8000 : port}
// HTTPS_PORT=${configFull.useHttps ? port : 8443}
// PUBLIC_URL=${protocol}://${host}${portStr ? `:${port}` : ""}
// DOMAIN=${host}
// ENABLE_AUTH=0
// ENABLE_GUESTS=1
// ENABLE_TRANSCRIPTION=0
// ENABLE_RECORDING=0
// ENABLE_PREJOIN_PAGE=0
// START_AUDIO_MUTED=0
// START_VIDEO_MUTED=0
// ENABLE_XMPP_WEBSOCKET=0
// ENABLE_P2P=1
// MAX_NUMBER_OF_PARTICIPANTS=10
// RESOLUTION_WIDTH=1280
// RESOLUTION_HEIGHT=720
// JWT_APP_ID=${configFull.appId}
// JWT_APP_SECRET=
// `;
const envPath = `${dockerComposePath}/.env`;
const resultadoEnv = await escreverArquivoSSH(sshConfig, envPath, envContent);
// const envPath = `${dockerComposePath}/.env`;
// const resultadoEnv = await escreverArquivoSSH(sshConfig, envPath, envContent);
if (!resultadoEnv.sucesso) {
return {
sucesso: false as const,
erro: `Erro ao atualizar .env: ${resultadoEnv.erro}`,
};
}
// if (!resultadoEnv.sucesso) {
// return {
// sucesso: false as const,
// erro: `Erro ao atualizar .env: ${resultadoEnv.erro}`,
// };
// }
detalhes.push(`✓ Arquivo .env atualizado: ${envPath}`);
}
// detalhes.push(`✓ Arquivo .env atualizado: ${envPath}`);
// }
// 2. Atualizar configuração do Prosody (conforme documentação oficial)
const prosodyConfigPath = `${basePath}/prosody/config/${host}.cfg.lua`;
const prosodyContent = `-- Configuração Prosody para ${host}
-- Gerada automaticamente pelo SGSE
-- Baseado na documentação oficial do Jitsi Meet
// // 2. Atualizar configuração do Prosody (conforme documentação oficial)
// const prosodyConfigPath = `${basePath}/prosody/config/${host}.cfg.lua`;
// const prosodyContent = `-- Configuração Prosody para ${host}
// -- Gerada automaticamente pelo SGSE
// -- Baseado na documentação oficial do Jitsi Meet
VirtualHost "${host}"
authentication = "anonymous"
modules_enabled = {
"bosh";
"websocket";
"ping";
"speakerstats";
"turncredentials";
"presence";
"conference_duration";
"stats";
}
c2s_require_encryption = false
allow_anonymous_s2s = false
bosh_max_inactivity = 60
bosh_max_polling = 5
bosh_max_stanzas = 5
// VirtualHost "${host}"
// authentication = "anonymous"
// modules_enabled = {
// "bosh";
// "websocket";
// "ping";
// "speakerstats";
// "turncredentials";
// "presence";
// "conference_duration";
// "stats";
// }
// c2s_require_encryption = false
// allow_anonymous_s2s = false
// bosh_max_inactivity = 60
// bosh_max_polling = 5
// bosh_max_stanzas = 5
Component "conference.${host}" "muc"
storage = "memory"
muc_room_locking = false
muc_room_default_public_jids = true
muc_room_cache_size = 1000
muc_log_presences = true
// Component "conference.${host}" "muc"
// storage = "memory"
// muc_room_locking = false
// muc_room_default_public_jids = true
// muc_room_cache_size = 1000
// muc_log_presences = true
Component "jitsi-videobridge.${host}"
component_secret = ""
// Component "jitsi-videobridge.${host}"
// component_secret = ""
Component "focus.${host}"
component_secret = ""
`;
// Component "focus.${host}"
// component_secret = ""
// `;
const resultadoProsody = await escreverArquivoSSH(sshConfig, prosodyConfigPath, prosodyContent);
// const resultadoProsody = await escreverArquivoSSH(sshConfig, prosodyConfigPath, prosodyContent);
if (!resultadoProsody.sucesso) {
return {
sucesso: false as const,
erro: `Erro ao atualizar Prosody: ${resultadoProsody.erro}`,
};
}
// if (!resultadoProsody.sucesso) {
// return {
// sucesso: false as const,
// erro: `Erro ao atualizar Prosody: ${resultadoProsody.erro}`,
// };
// }
detalhes.push(`✓ Configuração Prosody atualizada: ${prosodyConfigPath}`);
// detalhes.push(`✓ Configuração Prosody atualizada: ${prosodyConfigPath}`);
// 3. Atualizar configuração do Jicofo
const jicofoConfigPath = `${basePath}/jicofo/sip-communicator.properties`;
const jicofoContent = `# Configuração Jicofo
# Gerada automaticamente pelo SGSE
org.jitsi.jicofo.BRIDGE_MUC=JvbBrewery@internal.${host}
org.jitsi.jicofo.jid=XMPP_USER@${host}
org.jitsi.jicofo.BRIDGE_MUC_JID=MUC_BRIDGE_JID@internal.${host}
org.jitsi.jicofo.app.ID=${configFull.appId}
`;
// // 3. Atualizar configuração do Jicofo
// const jicofoConfigPath = `${basePath}/jicofo/sip-communicator.properties`;
// const jicofoContent = `# Configuração Jicofo
// # Gerada automaticamente pelo SGSE
// org.jitsi.jicofo.BRIDGE_MUC=JvbBrewery@internal.${host}
// org.jitsi.jicofo.jid=XMPP_USER@${host}
// org.jitsi.jicofo.BRIDGE_MUC_JID=MUC_BRIDGE_JID@internal.${host}
// org.jitsi.jicofo.app.ID=${configFull.appId}
// `;
const resultadoJicofo = await escreverArquivoSSH(sshConfig, jicofoConfigPath, jicofoContent);
// const resultadoJicofo = await escreverArquivoSSH(sshConfig, jicofoConfigPath, jicofoContent);
if (!resultadoJicofo.sucesso) {
return {
sucesso: false as const,
erro: `Erro ao atualizar Jicofo: ${resultadoJicofo.erro}`,
};
}
// if (!resultadoJicofo.sucesso) {
// return {
// sucesso: false as const,
// erro: `Erro ao atualizar Jicofo: ${resultadoJicofo.erro}`,
// };
// }
detalhes.push(`✓ Configuração Jicofo atualizada: ${jicofoConfigPath}`);
// detalhes.push(`✓ Configuração Jicofo atualizada: ${jicofoConfigPath}`);
// 4. Atualizar configuração do JVB
const jvbConfigPath = `${basePath}/jvb/sip-communicator.properties`;
const jvbContent = `# Configuração JVB (Jitsi Video Bridge)
# Gerada automaticamente pelo SGSE
org.jitsi.videobridge.AUTHORIZED_SOURCE_REGEXP=.*@${host}/.*
org.jitsi.videobridge.xmpp.user.shard.HOSTNAME=${host}
org.jitsi.videobridge.xmpp.user.shard.DOMAIN=auth.${host}
org.jitsi.videobridge.xmpp.user.shard.USERNAME=jvb
org.jitsi.videobridge.xmpp.user.shard.MUC_JIDS=JvbBrewery@internal.${host}
`;
// // 4. Atualizar configuração do JVB
// const jvbConfigPath = `${basePath}/jvb/sip-communicator.properties`;
// const jvbContent = `# Configuração JVB (Jitsi Video Bridge)
// # Gerada automaticamente pelo SGSE
// org.jitsi.videobridge.AUTHORIZED_SOURCE_REGEXP=.*@${host}/.*
// org.jitsi.videobridge.xmpp.user.shard.HOSTNAME=${host}
// org.jitsi.videobridge.xmpp.user.shard.DOMAIN=auth.${host}
// org.jitsi.videobridge.xmpp.user.shard.USERNAME=jvb
// org.jitsi.videobridge.xmpp.user.shard.MUC_JIDS=JvbBrewery@internal.${host}
// `;
const resultadoJvb = await escreverArquivoSSH(sshConfig, jvbConfigPath, jvbContent);
// const resultadoJvb = await escreverArquivoSSH(sshConfig, jvbConfigPath, jvbContent);
if (!resultadoJvb.sucesso) {
return {
sucesso: false as const,
erro: `Erro ao atualizar JVB: ${resultadoJvb.erro}`,
};
}
// if (!resultadoJvb.sucesso) {
// return {
// sucesso: false as const,
// erro: `Erro ao atualizar JVB: ${resultadoJvb.erro}`,
// };
// }
detalhes.push(`✓ Configuração JVB atualizada: ${jvbConfigPath}`);
// detalhes.push(`✓ Configuração JVB atualizada: ${jvbConfigPath}`);
// 5. Reiniciar containers Docker
if (dockerComposePath) {
const resultadoRestart = await executarComandoSSH(
sshConfig,
`cd "${dockerComposePath}" && docker-compose restart 2>&1 || docker compose restart 2>&1`
);
// // 5. Reiniciar containers Docker
// if (dockerComposePath) {
// const resultadoRestart = await executarComandoSSH(
// sshConfig,
// `cd "${dockerComposePath}" && docker-compose restart 2>&1 || docker compose restart 2>&1`
// );
if (!resultadoRestart.sucesso) {
return {
sucesso: false as const,
erro: `Erro ao reiniciar containers: ${resultadoRestart.erro}`,
};
}
// if (!resultadoRestart.sucesso) {
// return {
// sucesso: false as const,
// erro: `Erro ao reiniciar containers: ${resultadoRestart.erro}`,
// };
// }
detalhes.push(`✓ Containers Docker reiniciados`);
}
// detalhes.push(`✓ Containers Docker reiniciados`);
// }
// Atualizar timestamp de configuração no servidor
await ctx.runMutation(internal.configuracaoJitsi.marcarConfiguradoNoServidor, {
configId: args.configId,
});
// // Atualizar timestamp de configuração no servidor
// await ctx.runMutation(internal.configuracaoJitsi.marcarConfiguradoNoServidor, {
// configId: args.configId,
// });
return {
sucesso: true as const,
mensagem: "Configurações aplicadas com sucesso no servidor Jitsi",
detalhes: detalhes.join("\n"),
};
} catch (error: unknown) {
const errorMessage = error instanceof Error ? error.message : String(error);
return {
sucesso: false as const,
erro: `Erro ao aplicar configurações: ${errorMessage}`,
};
}
},
});
// return {
// sucesso: true as const,
// mensagem: "Configurações aplicadas com sucesso no servidor Jitsi",
// detalhes: detalhes.join("\n"),
// };
// } catch (error: unknown) {
// const errorMessage = error instanceof Error ? error.message : String(error);
// return {
// sucesso: false as const,
// erro: `Erro ao aplicar configurações: ${errorMessage}`,
// };
// }
// },
// });
/**
* Testar conexão SSH
*/
export const testarConexaoSSH = action({
args: {
sshHost: v.string(),
sshPort: v.optional(v.number()),
sshUsername: v.string(),
sshPassword: v.optional(v.string()),
sshKeyPath: v.optional(v.string()),
},
returns: v.union(
v.object({ sucesso: v.literal(true), mensagem: v.string() }),
v.object({ sucesso: v.literal(false), erro: v.string() })
),
handler: async (ctx, args): Promise<
| { sucesso: true; mensagem: string }
| { sucesso: false; erro: string }
> => {
try {
if (!args.sshPassword && !args.sshKeyPath) {
return {
sucesso: false as const,
erro: "Senha SSH ou caminho da chave deve ser fornecido",
};
}
// /**
// * Testar conexão SSH
// */
// export const testarConexaoSSH = action({
// args: {
// sshHost: v.string(),
// sshPort: v.optional(v.number()),
// sshUsername: v.string(),
// sshPassword: v.optional(v.string()),
// sshKeyPath: v.optional(v.string()),
// },
// returns: v.union(
// v.object({ sucesso: v.literal(true), mensagem: v.string() }),
// v.object({ sucesso: v.literal(false), erro: v.string() })
// ),
// handler: async (ctx, args): Promise<
// | { sucesso: true; mensagem: string }
// | { sucesso: false; erro: string }
// > => {
// try {
// if (!args.sshPassword && !args.sshKeyPath) {
// return {
// sucesso: false as const,
// erro: "Senha SSH ou caminho da chave deve ser fornecido",
// };
// }
const sshConfig: SSHConfig = {
host: args.sshHost,
port: args.sshPort || 22,
username: args.sshUsername,
password: args.sshPassword || undefined,
keyPath: args.sshKeyPath || undefined,
};
// const sshConfig: SSHConfig = {
// host: args.sshHost,
// port: args.sshPort || 22,
// username: args.sshUsername,
// password: args.sshPassword || undefined,
// keyPath: args.sshKeyPath || undefined,
// };
// Tentar executar um comando simples
const resultado = await executarComandoSSH(sshConfig, "echo 'SSH_OK'");
// // Tentar executar um comando simples
// const resultado = await executarComandoSSH(sshConfig, "echo 'SSH_OK'");
if (resultado.sucesso && resultado.output.includes("SSH_OK")) {
return {
sucesso: true as const,
mensagem: "Conexão SSH estabelecida com sucesso",
};
}
// if (resultado.sucesso && resultado.output.includes("SSH_OK")) {
// return {
// sucesso: true as const,
// mensagem: "Conexão SSH estabelecida com sucesso",
// };
// }
return {
sucesso: false as const,
erro: resultado.erro || "Falha ao estabelecer conexão SSH",
};
} catch (error: unknown) {
const errorMessage = error instanceof Error ? error.message : String(error);
return {
sucesso: false as const,
erro: `Erro ao testar SSH: ${errorMessage}`,
};
}
},
});
// return {
// sucesso: false as const,
// erro: resultado.erro || "Falha ao estabelecer conexão SSH",
// };
// } catch (error: unknown) {
// const errorMessage = error instanceof Error ? error.message : String(error);
// return {
// sucesso: false as const,
// erro: `Erro ao testar SSH: ${errorMessage}`,
// };
// }
// },
// });

View File

@@ -28,7 +28,6 @@
"@types/ssh2": "^1.15.5",
"better-auth": "catalog:",
"convex": "catalog:",
"nodemailer": "^7.0.10",
"ssh2": "^1.17.0"
"nodemailer": "^7.0.10"
}
}