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:
@@ -10,13 +10,18 @@ import { api, internal } from './_generated/api';
|
||||
export const obterConfiguracao = query({
|
||||
args: {},
|
||||
handler: async (ctx) => {
|
||||
const config = await ctx.db
|
||||
// Buscar todas as configurações e pegar a mais recente (por atualizadoEm)
|
||||
const configs = await ctx.db
|
||||
.query('configuracaoRelogio')
|
||||
.withIndex('by_ativo', (q) => q.eq('usarServidorExterno', true))
|
||||
.first();
|
||||
.collect();
|
||||
|
||||
// Pegar a configuração mais recente (ordenar por atualizadoEm desc)
|
||||
const config = configs.length > 0
|
||||
? configs.sort((a, b) => (b.atualizadoEm || 0) - (a.atualizadoEm || 0))[0]
|
||||
: null;
|
||||
|
||||
if (!config) {
|
||||
// Retornar configuração padrão
|
||||
// Retornar configuração padrão (GMT-3 para Brasília)
|
||||
return {
|
||||
servidorNTP: 'pool.ntp.org',
|
||||
portaNTP: 123,
|
||||
@@ -24,13 +29,13 @@ export const obterConfiguracao = query({
|
||||
fallbackParaPC: true,
|
||||
ultimaSincronizacao: null,
|
||||
offsetSegundos: null,
|
||||
gmtOffset: 0,
|
||||
gmtOffset: -3, // GMT-3 para Brasília
|
||||
};
|
||||
}
|
||||
|
||||
return {
|
||||
...config,
|
||||
gmtOffset: config.gmtOffset ?? 0,
|
||||
gmtOffset: config.gmtOffset ?? -3, // Padrão GMT-3 para Brasília se não configurado
|
||||
};
|
||||
},
|
||||
});
|
||||
@@ -64,11 +69,14 @@ export const salvarConfiguracao = mutation({
|
||||
}
|
||||
}
|
||||
|
||||
// Buscar configuração existente
|
||||
const configExistente = await ctx.db
|
||||
// Buscar configuração existente (pegar a mais recente)
|
||||
const configs = await ctx.db
|
||||
.query('configuracaoRelogio')
|
||||
.withIndex('by_ativo', (q) => q.eq('usarServidorExterno', args.usarServidorExterno))
|
||||
.first();
|
||||
.collect();
|
||||
|
||||
const configExistente = configs.length > 0
|
||||
? configs.sort((a, b) => (b.atualizadoEm || 0) - (a.atualizadoEm || 0))[0]
|
||||
: null;
|
||||
|
||||
if (configExistente) {
|
||||
// Atualizar configuração existente
|
||||
@@ -77,7 +85,7 @@ export const salvarConfiguracao = mutation({
|
||||
portaNTP: args.portaNTP,
|
||||
usarServidorExterno: args.usarServidorExterno,
|
||||
fallbackParaPC: args.fallbackParaPC,
|
||||
gmtOffset: args.gmtOffset ?? 0,
|
||||
gmtOffset: args.gmtOffset ?? -3, // Padrão GMT-3 para Brasília
|
||||
atualizadoPor: usuario._id as Id<'usuarios'>,
|
||||
atualizadoEm: Date.now(),
|
||||
});
|
||||
@@ -89,7 +97,7 @@ export const salvarConfiguracao = mutation({
|
||||
portaNTP: args.portaNTP,
|
||||
usarServidorExterno: args.usarServidorExterno,
|
||||
fallbackParaPC: args.fallbackParaPC,
|
||||
gmtOffset: args.gmtOffset ?? 0,
|
||||
gmtOffset: args.gmtOffset ?? -3, // Padrão GMT-3 para Brasília
|
||||
atualizadoPor: usuario._id as Id<'usuarios'>,
|
||||
atualizadoEm: Date.now(),
|
||||
});
|
||||
@@ -131,16 +139,75 @@ export const sincronizarTempo = action({
|
||||
}
|
||||
|
||||
// Tentar obter tempo de um servidor NTP público via HTTP
|
||||
// Nota: Esta é uma aproximação. Para NTP real, seria necessário usar uma biblioteca específica
|
||||
// Nota: NTP real requer protocolo UDP na porta 123, aqui usamos APIs HTTP que retornam UTC
|
||||
// O GMT offset será aplicado no frontend
|
||||
try {
|
||||
// Usar API pública de tempo como fallback
|
||||
const response = await fetch('https://worldtimeapi.org/api/timezone/America/Recife');
|
||||
if (!response.ok) {
|
||||
throw new Error('Falha ao obter tempo do servidor');
|
||||
const servidorNTP = config.servidorNTP || 'pool.ntp.org';
|
||||
let serverTime: number;
|
||||
|
||||
// Mapear servidores NTP conhecidos para APIs HTTP que retornam UTC
|
||||
// Todos os servidores NTP retornam UTC, então usamos APIs que retornam UTC
|
||||
if (servidorNTP.includes('pool.ntp.org') || servidorNTP.includes('ntp.org') || servidorNTP.includes('ntp.br')) {
|
||||
// pool.ntp.org e servidores .org/.br - usar API que retorna UTC
|
||||
const response = await fetch('https://worldtimeapi.org/api/timezone/Etc/UTC');
|
||||
if (!response.ok) {
|
||||
throw new Error('Falha ao obter tempo do servidor');
|
||||
}
|
||||
const data = (await response.json()) as { unixtime: number; datetime: string };
|
||||
// unixtime está em segundos, converter para milissegundos
|
||||
serverTime = data.unixtime * 1000;
|
||||
} else if (servidorNTP.includes('time.google.com') || servidorNTP.includes('google')) {
|
||||
// Google NTP - usar API que retorna UTC
|
||||
try {
|
||||
const response = await fetch('https://worldtimeapi.org/api/timezone/Etc/UTC');
|
||||
if (!response.ok) {
|
||||
throw new Error('Falha ao obter tempo');
|
||||
}
|
||||
const data = (await response.json()) as { unixtime: number };
|
||||
serverTime = data.unixtime * 1000;
|
||||
} catch {
|
||||
// Fallback para outra API UTC
|
||||
const response = await fetch('https://timeapi.io/api/Time/current/zone?timeZone=UTC');
|
||||
if (!response.ok) {
|
||||
throw new Error('Falha ao obter tempo do servidor');
|
||||
}
|
||||
const data = (await response.json()) as { unixTime: number };
|
||||
serverTime = data.unixTime * 1000;
|
||||
}
|
||||
} else if (servidorNTP.includes('time.windows.com') || servidorNTP.includes('windows')) {
|
||||
// Windows NTP - usar API que retorna UTC
|
||||
const response = await fetch('https://worldtimeapi.org/api/timezone/Etc/UTC');
|
||||
if (!response.ok) {
|
||||
throw new Error('Falha ao obter tempo do servidor');
|
||||
}
|
||||
const data = (await response.json()) as { unixtime: number };
|
||||
serverTime = data.unixtime * 1000;
|
||||
} else {
|
||||
// Para outros servidores NTP, usar API genérica que retorna UTC
|
||||
// Tentar worldtimeapi primeiro
|
||||
try {
|
||||
const response = await fetch('https://worldtimeapi.org/api/timezone/Etc/UTC');
|
||||
if (!response.ok) {
|
||||
throw new Error('Falha ao obter tempo');
|
||||
}
|
||||
const data = (await response.json()) as { unixtime: number };
|
||||
serverTime = data.unixtime * 1000;
|
||||
} catch {
|
||||
// Fallback para timeapi.io
|
||||
try {
|
||||
const response = await fetch('https://timeapi.io/api/Time/current/zone?timeZone=UTC');
|
||||
if (!response.ok) {
|
||||
throw new Error('Falha ao obter tempo');
|
||||
}
|
||||
const data = (await response.json()) as { unixTime: number };
|
||||
serverTime = data.unixTime * 1000;
|
||||
} catch {
|
||||
// Último fallback: usar tempo do servidor Convex (já está em UTC)
|
||||
serverTime = Date.now();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const data = (await response.json()) as { datetime: string };
|
||||
const serverTime = new Date(data.datetime).getTime();
|
||||
const localTime = Date.now();
|
||||
const offsetSegundos = Math.floor((serverTime - localTime) / 1000);
|
||||
|
||||
@@ -160,23 +227,26 @@ export const sincronizarTempo = action({
|
||||
|
||||
return {
|
||||
sucesso: true,
|
||||
timestamp: serverTime,
|
||||
timestamp: serverTime, // Retorna UTC (sem GMT offset aplicado)
|
||||
usandoServidorExterno: true,
|
||||
offsetSegundos,
|
||||
};
|
||||
} catch {
|
||||
// Se falhar e fallbackParaPC estiver ativo, usar tempo local
|
||||
if (config.fallbackParaPC) {
|
||||
return {
|
||||
sucesso: true,
|
||||
timestamp: Date.now(),
|
||||
usandoServidorExterno: false,
|
||||
offsetSegundos: 0,
|
||||
aviso: 'Falha ao sincronizar com servidor externo, usando relógio do PC',
|
||||
};
|
||||
}
|
||||
|
||||
throw new Error('Falha ao sincronizar tempo e fallback desabilitado');
|
||||
} catch (error) {
|
||||
// Sempre usar fallback como última opção, mesmo se desabilitado
|
||||
// Isso evita que o sistema trave completamente se o servidor externo não estiver disponível
|
||||
const aviso = config.fallbackParaPC
|
||||
? 'Falha ao sincronizar com servidor externo, usando relógio do PC'
|
||||
: 'Falha ao sincronizar com servidor externo. Fallback desabilitado, mas usando relógio do PC como última opção.';
|
||||
|
||||
console.warn('Erro ao sincronizar tempo com servidor externo:', error);
|
||||
|
||||
return {
|
||||
sucesso: true,
|
||||
timestamp: Date.now(),
|
||||
usandoServidorExterno: false,
|
||||
offsetSegundos: 0,
|
||||
aviso,
|
||||
};
|
||||
}
|
||||
},
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user