feat: enhance time synchronization and Jitsi configuration handling

- Implemented a comprehensive time synchronization mechanism that applies GMT offsets based on user configuration, ensuring accurate timestamps across the application.
- Updated the Jitsi configuration to include SSH settings, allowing for better integration with Docker setups.
- Refactored the backend queries and mutations to handle the new SSH configuration fields, ensuring secure and flexible server management.
- Enhanced error handling and logging for time synchronization processes, providing clearer feedback for users and developers.
This commit is contained in:
2025-11-22 18:18:16 -03:00
parent 54089f5eca
commit c056506ce5
17 changed files with 1765 additions and 257 deletions

View File

@@ -190,9 +190,51 @@
const informacoesDispositivo = await obterInformacoesDispositivo();
coletandoInfo = false;
// Obter tempo sincronizado
const timestamp = await obterTempoServidor(client);
const sincronizadoComServidor = true; // Sempre true quando usamos obterTempoServidor
// Obter tempo sincronizado e aplicar GMT offset (igual ao relógio)
const configRelogio = await client.query(api.configuracaoRelogio.obterConfiguracao, {});
// Usar gmtOffset da configuração, sem valor padrão, pois 0 é um valor válido
const gmtOffset = configRelogio.gmtOffset ?? 0;
let timestampBase: number;
if (configRelogio.usarServidorExterno) {
try {
const resultado = await client.action(api.configuracaoRelogio.sincronizarTempo, {});
if (resultado.sucesso && resultado.timestamp) {
timestampBase = resultado.timestamp;
} else {
timestampBase = await obterTempoServidor(client);
}
} catch (error) {
console.warn('Erro ao sincronizar com servidor externo:', error);
if (configRelogio.fallbackParaPC) {
timestampBase = Date.now();
} else {
timestampBase = await obterTempoServidor(client);
}
}
} else {
// Usar relógio do PC (sem sincronização com servidor)
timestampBase = Date.now();
}
// Aplicar GMT offset ao timestamp
// Quando GMT é 0, compensar o timezone local do navegador para que o timestamp
// represente o horário local (não UTC), evitando que apareça 3 horas a mais
let timestamp: number;
if (gmtOffset !== 0) {
// Aplicar offset configurado
timestamp = timestampBase + (gmtOffset * 60 * 60 * 1000);
} else {
// Quando GMT = 0, ajustar para horário local do navegador
// getTimezoneOffset() retorna minutos POSITIVOS para fusos ATRÁS de UTC
// Exemplo: Brasil (UTC-3) retorna 180 minutos
// Subtrair esses minutos para que o timestamp represente o horário local
const timezoneOffset = new Date().getTimezoneOffset(); // Offset em minutos
timestamp = timestampBase - (timezoneOffset * 60 * 1000); // Subtrair minutos em milissegundos
}
// Sincronizado apenas se usar servidor externo e sincronização foi bem-sucedida
const sincronizadoComServidor = configRelogio.usarServidorExterno && timestampBase !== Date.now();
// Upload da imagem (obrigatória agora)
let imagemId: Id<'_storage'> | undefined = undefined;
@@ -275,9 +317,47 @@
// Se capturou a foto, mostrar modal de confirmação
if (blob && capturandoAutomaticamente) {
capturandoAutomaticamente = false;
// Obter data e hora sincronizada do servidor
// Obter data e hora sincronizada do servidor com GMT offset (igual ao relógio)
try {
const timestamp = await obterTempoServidor(client);
const configRelogio = await client.query(api.configuracaoRelogio.obterConfiguracao, {});
// Usar gmtOffset da configuração, sem valor padrão, pois 0 é um valor válido
const gmtOffset = configRelogio.gmtOffset ?? 0;
let timestampBase: number;
if (configRelogio.usarServidorExterno) {
try {
const resultado = await client.action(api.configuracaoRelogio.sincronizarTempo, {});
if (resultado.sucesso && resultado.timestamp) {
timestampBase = resultado.timestamp;
} else {
timestampBase = await obterTempoServidor(client);
}
} catch (error) {
console.warn('Erro ao sincronizar com servidor externo:', error);
if (configRelogio.fallbackParaPC) {
timestampBase = Date.now();
} else {
timestampBase = await obterTempoServidor(client);
}
}
} else {
// Usar relógio do PC (sem sincronização com servidor)
timestampBase = Date.now();
}
// Aplicar GMT offset ao timestamp
// Quando GMT é 0, usar timestamp UTC puro e deixar toLocaleTimeString() fazer a conversão automática
// Quando GMT ≠ 0, aplicar offset configurado ao timestamp
let timestamp: number;
if (gmtOffset !== 0) {
// Aplicar offset configurado
timestamp = timestampBase + (gmtOffset * 60 * 60 * 1000);
} else {
// Quando GMT = 0, manter timestamp UTC puro
// O toLocaleTimeString() converterá automaticamente para o timezone local do navegador
timestamp = timestampBase;
}
const dataObj = new Date(timestamp);
const data = dataObj.toLocaleDateString('pt-BR');
const hora = dataObj.toLocaleTimeString('pt-BR', { hour: '2-digit', minute: '2-digit', second: '2-digit' });

View File

@@ -17,6 +17,8 @@
async function atualizarTempo() {
try {
const config = await client.query(api.configuracaoRelogio.obterConfiguracao, {});
// Usar gmtOffset da configuração, sem valor padrão, pois 0 é um valor válido
// Se não estiver configurado, usar null e tratar como 0
const gmtOffset = config.gmtOffset ?? 0;
let timestampBase: number;
@@ -45,16 +47,25 @@
}
}
} else {
// Usar tempo do servidor Convex
timestampBase = await obterTempoServidor(client);
sincronizado = true;
// Usar relógio do PC (sem sincronização com servidor)
timestampBase = obterTempoPC();
sincronizado = false;
usandoServidorExterno = false;
erro = null;
erro = 'Usando relógio do PC';
}
// Aplicar GMT offset ao timestamp
// O timestamp está em UTC, adicionar o offset em horas
const timestampAjustado = timestampBase + (gmtOffset * 60 * 60 * 1000);
// Quando GMT é 0, usar timestamp UTC puro e deixar toLocaleTimeString() fazer a conversão automática
// Quando GMT ≠ 0, aplicar offset configurado ao timestamp
let timestampAjustado: number;
if (gmtOffset !== 0) {
// Aplicar offset configurado
timestampAjustado = timestampBase + (gmtOffset * 60 * 60 * 1000);
} else {
// Quando GMT = 0, manter timestamp UTC puro
// O toLocaleTimeString() converterá automaticamente para o timezone local do navegador
timestampAjustado = timestampBase;
}
tempoAtual = new Date(timestampAjustado);
} catch (error) {
console.error('Erro ao obter tempo:', error);
@@ -120,7 +131,7 @@
<span class="text-warning">{erro}</span>
{:else}
<Clock class="h-4 w-4 text-base-content/50" />
<span class="text-base-content/50">Sincronizando...</span>
<span class="text-base-content/50">Usando relógio do PC</span>
{/if}
</div>
</div>