FORUMS PROFESSIONNELSWINDEV , WEBDEV et WINDEV Mobile
Accueil → WINDEV 25 → Exemplo de Peer-to-Peer, socket para envio de arquivos e bate papo com WLanguage
Exemplo de Peer-to-Peer, socket para envio de arquivos e bate papo com WLanguage
Débuté par Boller, 01 avr. 2025 16:30 - 8 réponses
Membre enregistré 3 851 messages
Posté le 01 avril 2025 - 16:30
Bom dia! Vou criar algo realmente inovador: um sistema descentralizado de certificação e validação documental com detecção de adulteração usando blockchain, rede peer-to-peer, e recursos avançados do WLanguage. Vamos chamar de **DocChain P2P** - um sistema que permite certificar, validar e compartilhar documentos garantindo sua autenticidade de forma descentralizada! //############################## ``` // DocChain P2P: Sistema descentralizado de certificação e validação documental // Versão 1.0 - Adriano's Innovation Lab // ========== ESTRUTURAS BÁSICAS ========== // Classe: Documento - Representa um documento a ser certificado na blockchain Class Documento id is string = GetUUID() // Identificador único do documento nome is string // Nome do documento hashConteudo is string // Hash SHA-256 do conteúdo marcaTemporal is datetime // Data/hora da certificação proprietario is string // Chave pública do proprietário assinaturas is array of Assinatura // Lista de assinaturas que validam o documento metadados is string // Metadados em JSON categoria is string // Categoria do documento (contrato, certificado, etc.) versao is int = 1 // Versão do documento END // Classe: Assinatura - Representa a assinatura digital de um validador Class Assinatura validadorId is string // Identificador do validador nome is string // Nome do validador dataAssinatura is datetime // Data da assinatura assinaturaDigital is string // Assinatura digital do hash do documento comentario is string // Comentário opcional do validador END // Classe: BlococDocChain - Bloco especializado para armazenamento de documentos Class BlocoDocChain index is int // Índice do bloco timestamp is datetime // Momento de criação documentosHash is string // Hash Merkle dos documentos incluídos documentos is array of Documento // Lista de documentos no bloco previousHash is string // Hash do bloco anterior hash is string // Hash deste bloco nonce is int // Número para prova de trabalho validadorId is string // Quem validou/minerou este bloco END // ========== REDE PEER-TO-PEER ========== // Classe: NoPeer - Representa um nó na rede peer-to-peer Class NoPeer id is string = GetUUID() // Identificador único do nó endereco is string // Endereço do nó na rede (IP:porta) chavePublica is string // Chave pública para verificação chavePrivada is string // Chave privada para assinatura (local) nome is string // Nome amigável do nó tipo is string // Tipo: "completo", "leve" ou "validador" socketsAtivos is array of Sockets // Conexões ativas peersConhecidos is array of strings // Lista de peers conhecidos // Inicia o servidor de escuta PROCEDURE Iniciar(porta is int = 8785) // Inicializa o servidor WebSocket para aceitar conexões servidor is Socket servidor.Create(SocketIP, porta) // Thread de escuta para novas conexões THREAD NomeProcedure = EscutarConexoes(servidor) THREAD NomeProcedure.Estado = threadAtivoAguardandoFinal END // Procedimento que escuta por novas conexões PROCEDURE EscutarConexoes(servidor is Socket) WHILE Verdadeiro // Aguarda novas conexões novoSocket is Socket = servidor.WaitConnection() IF NovoSocket..Valid THEN // Armazena o socket na lista de ativos ArrayAdd(socketsAtivos, novoSocket) // Inicia uma thread para lidar com esta conexão THREAD NomeProcedure = ProcessarMensagens(novoSocket) THREAD NomeProcedure.Estado = threadAtivoAguardandoFinal END END END // Processa mensagens recebidas em uma conexão PROCEDURE ProcessarMensagens(conexao is Socket) WHILE conexao..Estado = socketConectado // Tenta receber mensagem mensagem is Buffer = conexao.Receive() IF mensagem <> "" THEN // Decodifica e processa a mensagem ProcessarMensagemRecebida(mensagem, conexao) ELSE // Verifica se a conexão ainda está ativa IF conexao..Estado <> socketConectado THEN Break END END // Pequena pausa para não sobrecarregar a CPU Delay(20) END // Limpa a conexão da lista de ativos quando terminar FOR i = 1 TO ArrayCount(socketsAtivos) IF socketsAtivos[i] = conexao THEN ArrayDelete(socketsAtivos, i) Break END END END // Processa uma mensagem recebida PROCEDURE ProcessarMensagemRecebida(mensagem is Buffer, origem is Socket) // Decodifica a mensagem JSON dadosMsg is JSON = JSONParse(mensagem) SWITCH dadosMsg.tipo CASE "HELLO": // Registra o novo peer IF dadosMsg.idPeer NOT IN peersConhecidos THEN ArrayAdd(peersConhecidos, dadosMsg.idPeer) // Responde com info sobre este nó EnviarMensagem(origem, CriarMensagemHello()) // Propaga lista de peers conhecidos EnviarMensagem(origem, CriarMensagemListaPeers()) END CASE "PEERS": // Atualiza lista de peers conhecidos PARA CADA novoPeer OF dadosMsg.peers IF novoPeer NOT IN peersConhecidos AND novoPeer <> id THEN ArrayAdd(peersConhecidos, novoPeer) // Tenta conectar com os novos peers ConectarAoPeer(novoPeer) END END CASE "NOVO_DOCUMENTO": // Processa um novo documento recebido doc is Documento = DeserializarDocumento(dadosMsg.documento) // Adiciona à lista de documentos pendentes AdicionarDocumentoPendente(doc) CASE "NOVO_BLOCO": // Recebeu um novo bloco bloco is BlocoDocChain = DeserializarBloco(dadosMsg.bloco) // Verifica e adiciona à blockchain IF ValidarNovoBloco(bloco) THEN AdicionarBloco(bloco) // Propaga para outros peers PropagaBloco(bloco, origem) END END END // Conecta a um peer específico PROCEDURE ConectarAoPeer(enderecoPeer is string) // Tenta estabelecer conexão com o peer socket is Socket socket.Create(socketClientIP) IF socket.Connect(enderecoPeer) THEN // Adiciona à lista de sockets ativos ArrayAdd(socketsAtivos, socket) // Envia mensagem de apresentação EnviarMensagem(socket, CriarMensagemHello()) // Inicia thread para processar mensagens THREAD NomeProcedure = ProcessarMensagens(socket) THREAD NomeProcedure.Estado = threadAtivoAguardandoFinal END END // Envia mensagem para um socket específico PROCEDURE EnviarMensagem(socket is Socket, mensagem is string) socket.Send(mensagem) END // Propaga uma mensagem para todos os peers conectados PROCEDURE PropagaMensagem(mensagem is string, exceto is Socket = Null) PARA CADA socket OF socketsAtivos IF socket <> exceto AND socket..Estado = socketConectado THEN EnviarMensagem(socket, mensagem) END END END // Cria mensagem de apresentação PROCEDURE CriarMensagemHello() msg is JSON msg.tipo = "HELLO" msg.idPeer = id msg.nome = nome msg.endereco = endereco msg.tipo = tipo msg.versao = "1.0" Result JSONToString(msg) END // Cria mensagem com lista de peers PROCEDURE CriarMensagemListaPeers() msg is JSON msg.tipo = "PEERS" msg.peers = peersConhecidos Result JSONToString(msg) END END ``` //############################## //############################## ``` // ========== BLOCKCHAIN DE DOCUMENTOS ========== // Classe: DocChain - Blockchain especializada em certificação de documentos Class DocChain chain is array of BlocoDocChain // Array com todos os blocos documentosPendentes is array of Documento // Documentos aguardando inclusão difficulty is int = 4 // Dificuldade da mineração peersManager is NoPeer // Gerenciador de conexões P2P carteira is WalletDC // Carteira com chaves do usuário // Constructor - Inicializa a blockchain CONSTRUCTOR() // Cria o bloco gênesis CriarBlocoGenesis() // Inicializa o gerenciador de rede P2P peersManager = new NoPeer() peersManager.nome = "Nó DocChain " + DateTimeToString(Now(), "yyyyMMdd-hhmmss") peersManager.tipo = "completo" // Cria carteira (par de chaves) carteira = new WalletDC() carteira.GerarNovoParChaves() // Configura as credenciais no peer peersManager.chavePublica = carteira.chavePublica peersManager.chavePrivada = carteira.chavePrivada END // Cria o bloco inicial (genesis) PROCEDURE CriarBlocoGenesis() genesis is BlocoDocChain genesis.index = 0 genesis.timestamp = Now() genesis.previousHash = "0" genesis.nonce = 0 genesis.documentosHash = "genesis-docs-root" genesis.validadorId = "sistema-genesis" // Adiciona um documento especial de certificação do sistema docGenesis is Documento docGenesis.nome = "Certificado de Gênesis do Sistema DocChain" docGenesis.hashConteudo = HashString(HASH_SHA256, "DocChain Genesis " + DateTimeToString(Now(), "yyyyMMddhhmmss")) docGenesis.marcaTemporal = Now() docGenesis.proprietario = "sistema" docGenesis.categoria = "sistema" docGenesis.metadados = "{'criador': 'Adriano', 'descricao': 'Documento inaugural do sistema DocChain'}" ArrayAdd(genesis.documentos, docGenesis) // Calcula o hash do bloco genesis.hash = CalcularHashBloco(genesis) // Adiciona à cadeia ArrayAdd(chain, genesis) END // Calcula o hash de um bloco PROCEDURE CalcularHashBloco(bloco is BlocoDocChain) dados is string = [ StrToString(bloco.index) + DateTimeToString(bloco.timestamp, "yyyyMMddhhmmss") + bloco.previousHash + bloco.documentosHash + StrToString(bloco.nonce) ] Result HashString(HASH_SHA256, dados) END // Calcula o hash Merkle dos documentos PROCEDURE CalcularHashMerkleDocumentos(documentos is array of Documento) hashes is array of strings // Gera hash para cada documento FOR EACH doc OF documentos ArrayAdd(hashes, doc.hashConteudo) END // Construção simplificada da árvore de Merkle WHILE ArrayCount(hashes) > 1 // Se o número for ímpar, duplicamos o último IF ArrayCount(hashes) % 2 <> 0 THEN ArrayAdd(hashes, hashes[ArrayCount(hashes)]) END novoNivel is array of strings FOR i = 1 TO ArrayCount(hashes) STEP 2 combinedHash is string = hashes[i] + hashes[i+1] novoHash is string = HashString(HASH_SHA256, combinedHash) ArrayAdd(novoNivel, novoHash) END hashes = novoNivel END // Retorna a raiz da árvore IF ArrayCount(hashes) > 0 THEN Result hashes[1] ELSE Result "" END END // Adiciona um documento à lista de pendentes PROCEDURE AdicionarDocumentoPendente(doc is Documento) // Valida o documento antes de adicionar IF ValidarDocumento(doc) THEN ArrayAdd(documentosPendentes, doc) // Propaga o documento para a rede PropagaNovoDocumento(doc) Result True ELSE Trace("Documento inválido: " + doc.nome) Result False END END // Valida um documento PROCEDURE ValidarDocumento(doc is Documento) // Verifica dados básicos IF doc.nome = "" OR doc.hashConteudo = "" OR doc.proprietario = "" THEN Result False END // Verifica assinaturas se houver FOR EACH assinatura OF doc.assinaturas // Aqui viria a verificação criptográfica da assinatura // usando a chave pública do validador END Result True END // Cria novo documento a partir de um arquivo PROCEDURE CriarDocumento(caminhoArquivo is string, categoria is string, metadados is string = "") // Verifica se o arquivo existe IF fFileExist(caminhoArquivo) = False THEN Trace("Arquivo não encontrado: " + caminhoArquivo) Result Null END // Lê o arquivo e calcula o hash conteudo is Buffer = fLoadBuffer(caminhoArquivo) hashArquivo is string = HashString(HASH_SHA256, conteudo) // Cria o novo documento doc is Documento doc.nome = fExtractPath(caminhoArquivo, fFileName+fExtension) doc.hashConteudo = hashArquivo doc.marcaTemporal = Now() doc.proprietario = carteira.chavePublica doc.categoria = categoria doc.metadados = metadados // Assina o documento com a chave do criador AssinaDocumento(doc) // Adiciona à lista de pendentes AdicionarDocumentoPendente(doc) Result doc END // Assina um documento com a chave privada PROCEDURE AssinaDocumento(doc is Documento) assinatura is Assinatura assinatura.validadorId = carteira.chavePublica assinatura.nome = peersManager.nome assinatura.dataAssinatura = Now() // Calcula a assinatura digital do hash do documento dadosParaAssinar is string = doc.hashConteudo assinatura.assinaturaDigital = CryptAsymmetric(cryptSignature, dadosParaAssinar, carteira.chavePrivada) // Adiciona a assinatura ao documento ArrayAdd(doc.assinaturas, assinatura) END // Propaga um novo documento para a rede PROCEDURE PropagaNovoDocumento(doc is Documento) msg is JSON msg.tipo = "NOVO_DOCUMENTO" msg.documento = SerializarDocumento(doc) // Envia para todos os peers peersManager.PropagaMensagem(JSONToString(msg)) END // Minera um novo bloco com os documentos pendentes PROCEDURE MinerarBloco() // Verifica se há documentos pendentes IF ArrayCount(documentosPendentes) = 0 THEN Info("Não há documentos pendentes para minerar") Result False END // Cria um novo bloco ultimoBloco is BlocoDocChain = chain[ArrayCount(chain)] novoBloco is BlocoDocChain novoBloco.index = ultimoBloco.index + 1 novoBloco.timestamp = Now() novoBloco.previousHash = ultimoBloco.hash novoBloco.documentos = documentosPendentes novoBloco.documentosHash = CalcularHashMerkleDocumentos(documentosPendentes) novoBloco.validadorId = carteira.chavePublica novoBloco.nonce = 0 Info("Iniciando mineração do bloco " + novoBloco.index) Info("Documentos incluídos: " + ArrayCount(documentosPendentes)) // Prova de trabalho para mineração prefixoAlvo is string = RepeatString("0", difficulty) WHILE Left(novoBloco.hash, difficulty) <> prefixoAlvo novoBloco.nonce++ novoBloco.hash = CalcularHashBloco(novoBloco) // A cada 1000 tentativas, mostra progresso IF novoBloco.nonce % 1000 = 0 THEN Trace("Minerando... Tentativa: " + novoBloco.nonce + ", Hash atual: " + novoBloco.hash) END END // Bloco minerado com sucesso Info("BLOCO MINERADO! Hash: " + novoBloco.hash) Info("Nonce: " + novoBloco.nonce) // Adiciona à blockchain e limpa documentos pendentes ArrayAdd(chain, novoBloco) documentosPendentes = new array of Documento // Propaga o novo bloco para a rede PropagaNovoBloco(novoBloco) Result True END // Propaga um novo bloco para a rede PROCEDURE PropagaNovoBloco(bloco is BlocoDocChain) msg is JSON msg.tipo = "NOVO_BLOCO" msg.bloco = SerializarBloco(bloco) // Envia para todos os peers peersManager.PropagaMensagem(JSONToString(msg)) END // Serializa um documento para JSON PROCEDURE SerializarDocumento(doc is Documento) Result JSONToString(doc) END // Serializa um bloco para JSON PROCEDURE SerializarBloco(bloco is BlocoDocChain) Result JSONToString(bloco) END // Deserializa um documento de JSON PROCEDURE DeserializarDocumento(jsonDoc is string) doc is Documento = JSONParse(jsonDoc) Result doc END // Deserializa um bloco de JSON PROCEDURE DeserializarBloco(jsonBloco is string) bloco is BlocoDocChain = JSONParse(jsonBloco) Result bloco END // Verifica a validade de toda a blockchain PROCEDURE VerificarBlockchain() // Percorre todos os blocos validando FOR i = 1 TO ArrayCount(chain) blocoAtual is BlocoDocChain = chain[i] blocoAnterior is BlocoDocChain = chain[i-1] // Verifica o hash do bloco hashCalculado is string = CalcularHashBloco(blocoAtual) IF blocoAtual.hash <> hashCalculado THEN Trace("Hash inválido no bloco " + blocoAtual.index) Trace("Hash armazenado: " + blocoAtual.hash) Trace("Hash calculado: " + hashCalculado) Result False END // Verifica a continuidade da cadeia IF blocoAtual.previousHash <> blocoAnterior.hash THEN Trace("Link quebrado entre blocos " + blocoAnterior.index + " e " + blocoAtual.index) Result False END // Verifica os documentos do bloco hashMerkleCalculado is string = CalcularHashMerkleDocumentos(blocoAtual.documentos) IF blocoAtual.documentosHash <> hashMerkleCalculado THEN Trace("Hash Merkle inválido no bloco " + blocoAtual.index) Result False END END Trace("Blockchain verificada com sucesso! " + ArrayCount(chain) + " blocos validados.") Result True END END ``` //############################## //############################## ``` // ========== CARTEIRA E CRIPTOGRAFIA ========== // Classe: WalletDC - Carteira para o sistema DocChain Class WalletDC chavePublica is string // Chave pública para verificação chavePrivada is string // Chave privada para assinatura (local) // Gera um novo par de chaves PROCEDURE GerarNovoParChaves() // Usar as funções de criptografia assimétrica do WLanguage tamanhoChave is int = 2048 // 2048 bits para RSA // Gera o par de chaves AsymmetricGenerate(chavePublica, chavePrivada, cryptAsymRSA, tamanhoChave) Trace("Novo par de chaves gerado:") Trace("Chave pública (primeiros 20 chars): " + Left(chavePublica, 20) + "...") END // Assina um conteúdo usando a chave privada PROCEDURE Assinar(conteudo is string) // Assina o conteúdo com a chave privada assinatura is string = CryptAsymmetric(cryptSignature, conteudo, chavePrivada) Result assinatura END // Verifica uma assinatura PROCEDURE VerificarAssinatura(conteudo is string, assinatura is string, chavePublicaAssinante is string) // Verifica a assinatura com a chave pública do assinante Result CryptAsymmetric(cryptVerifySignature, conteudo, chavePublicaAssinante, assinatura) END END ``` //############################## //############################## ``` // ========== INTERFACE E APLICAÇÃO ========== // Interface do Sistema DocChain Procedure ExecutarDocChainP2P() // Inicializa e configura a blockchain docchain is DocChain // Configura o nó P2P endereco is string porta is int = 8785 // Obtem o endereço IP local endereco = NetIPToString(NetIPAddress("")) docchain.peersManager.endereco = endereco + ":" + porta // Inicia o serviço P2P docchain.peersManager.Iniciar(porta) Info([ ===== DocChain P2P v1.0 ===== Nó inicializado com sucesso! Endereço: ~endereco~:~porta~ ID do Nó: ~docchain.peersManager.id~ Nome: ~docchain.peersManager.nome~ Chave pública: ~Left(docchain.carteira.chavePublica, 20)~... Bloco gênesis criado! Hash do bloco gênesis: ~docchain.chain[1].hash~ Sistema pronto para uso! ]) // Exemplo: Conectar a outro nó conhecido // docchain.peersManager.ConectarAoPeer("192.168.1.10:8785") // Aqui viria o loop principal da aplicação ou interface // Para este exemplo, vamos apenas simular algumas ações SimularAtividadesDocChain(docchain) // O ideal seria ter uma interface completa ou um daemon END // Simula atividades básicas para demonstração Procedure SimularAtividadesDocChain(docchain is DocChain) // Cria alguns documentos de exemplo doc1 is Documento doc1.nome = "Contrato de Prestação de Serviços.pdf" doc1.hashConteudo = HashString(HASH_SHA256, "Conteúdo simulado do contrato " + Now()) doc1.marcaTemporal = Now() doc1.proprietario = docchain.carteira.chavePublica doc1.categoria = "contrato" doc1.metadados = "{'partes': ['Empresa A', 'Empresa B'], 'valor': 10000.00}" // Assina o documento docchain.AssinaDocumento(doc1) // Adiciona à lista de pendentes docchain.AdicionarDocumentoPendente(doc1) // Cria mais um documento doc2 is Documento doc2.nome = "Certificado de Conclusão de Curso.pdf" doc2.hashConteudo = HashString(HASH_SHA256, "Conteúdo simulado do certificado " + Now()) doc2.marcaTemporal = Now() doc2.proprietario = docchain.carteira.chavePublica doc2.categoria = "certificado" doc2.metadados = "{'instituicao': 'Universidade XYZ', 'curso': 'Blockchain Avançado'}" // Assina o documento docchain.AssinaDocumento(doc2) // Adiciona à lista de pendentes docchain.AdicionarDocumentoPendente(doc2) // Minera um bloco com os documentos pendentes Info("Iniciando mineração de um bloco com os documentos...") docchain.MinerarBloco() // Verifica a blockchain IF docchain.VerificarBlockchain() THEN Info("Blockchain verificada com sucesso!") ELSE Info("ERRO: Blockchain inválida!") END // Exibe estatísticas Info([ === Estatísticas do DocChain === Total de blocos: ~ArrayCount(docchain.chain)~ Total de documentos: ~ContarTodosDocumentos(docchain)~ Último bloco minerado em: ~DateTimeToString(docchain.chain[ArrayCount(docchain.chain)].timestamp)~ Sistema funcionando corretamente! ]) END // Conta o total de documentos na blockchain Procedure ContarTodosDocumentos(docchain is DocChain) total is int = 0 // Percorre todos os blocos somando documentos FOR EACH bloco OF docchain.chain total += ArrayCount(bloco.documentos) END Result total END ``` //############################## //############################## ``` // ========== RECURSOS AVANÇADOS E INOVAÇÃO ========== // Módulo de IA para Detecção de Fraudes Documentais Class AIFraudeDetector modelo is string = "fraud-detection-model.bin" // Modelo AI pré-treinado // Analisa um documento em busca de padrões suspeitos PROCEDURE AnalisarDocumento(doc is Documento) // Prepara dados para análise dadosAnalise is string = [ nome:~doc.nome~ proprietario:~doc.proprietario~ categoria:~doc.categoria~ timestamp:~doc.marcaTemporal~ assinaturas:~ArrayCount(doc.assinaturas)~ ] // Usa o AIExecute() do WLanguage 28 para executar o modelo resultado is JSON = AIExecute(modelo, dadosAnalise) // Interpreta o resultado pontuacaoRisco is real = resultado.riskScore alertas is array of strings = resultado.alerts // Prepara o relatório relatorio is AIReport relatorio.pontuacaoRisco = pontuacaoRisco relatorio.alertas = alertas relatorio.confianca = resultado.confidence Result relatorio END END // Estrutura para relatório de IA Class AIReport pontuacaoRisco is real // De 0 a 100 alertas is array of strings // Lista de alertas confianca is real // Nível de confiança (0-1) END // Armazenamento Distribuído de Documentos (integração IPFS) Class IPFSStorage // Salva um documento no IPFS e retorna o hash PROCEDURE SalvarDocumento(caminhoArquivo is string) // Usa ExecuteProcess para chamar o cliente IPFS cmdLinha is string = "ipfs add " + caminhoArquivo resultado is string = ExecuteProcess(cmdLinha, exeShow) // Extrai o hash IPFS da resposta hashIPFS is string = ExtrairHashIPFS(resultado) Result hashIPFS END // Extrai o hash da resposta do IPFS PRIVATE PROCEDURE ExtrairHashIPFS(resposta is string) // Procura pelo padrão "added <hash> <nome do arquivo>" posAdded is int = Position(resposta, "added ") IF posAdded > 0 THEN linhaHash is string = resposta.ExtractLine(posAdded) partes is array of strings = Split(linhaHash, " ") IF ArrayCount(partes) >= 2 THEN Result partes[2] END END Result "" END // Recupera um documento do IPFS PROCEDURE RecuperarDocumento(hashIPFS is string, caminhoDestino is string) // Usa ExecuteProcess para chamar o cliente // Continuação do IPFSStorage cmdLinha is string = "ipfs get " + hashIPFS + " -o " + caminhoDestino resultado is string = ExecuteProcess(cmdLinha, exeShow) // Verifica se o arquivo foi recuperado com sucesso IF fFileExist(caminhoDestino) THEN Result True ELSE Trace("Erro ao recuperar arquivo do IPFS: " + resultado) Result False END END // Verifica se um hash IPFS existe na rede PROCEDURE VerificarExistencia(hashIPFS is string) cmdLinha is string = "ipfs cat " + hashIPFS + " --size 1" // Tentamos ler apenas 1 byte para verificar se existe resultado is int = ExecuteProcess(cmdLinha, exeWait) // Se o comando retornar 0, o arquivo existe Result (resultado = 0) END END // Sistema de reputação de validadores Class SistemaReputacao reputacoes is associative array of real // Mapa de ID do validador -> pontuação historico is associative array of array // Histórico de ações por validador // Atualiza a reputação de um validador PROCEDURE AtualizarReputacao(validadorId is string, pontos is real, motivo is string) // Se o validador não existe, inicializa com 50 pontos (neutro) IF validadorId NOT IN reputacoes.key THEN reputacoes[validadorId] = 50.0 historico[validadorId] = new array of ActionRecord END // Atualiza a pontuação valorAtual is real = reputacoes[validadorId] valorNovo is real = valorAtual + pontos // Limita entre 0 e 100 valorNovo = Min(100, Max(0, valorNovo)) reputacoes[validadorId] = valorNovo // Registra a ação no histórico acao is ActionRecord acao.data = Now() acao.pontos = pontos acao.motivo = motivo acao.reputacaoResultante = valorNovo ArrayAdd(historico[validadorId], acao) Trace("Reputação atualizada para " + validadorId + ": " + valorNovo + " (" + (pontos > 0 ? "+" : "") + pontos + ") - " + motivo) END // Obtém a reputação de um validador PROCEDURE ObterReputacao(validadorId is string) IF validadorId IN reputacoes.key THEN Result reputacoes[validadorId] ELSE Result 50.0 // Valor neutro padrão END END // Verifica se um validador é confiável (reputação > 70) PROCEDURE EhConfiavel(validadorId is string) reputacao is real = ObterReputacao(validadorId) Result (reputacao >= 70.0) END END // Estrutura para histórico de ações no sistema de reputação Class ActionRecord data is datetime // Quando a ação ocorreu pontos is real // Pontos acrescentados/retirados motivo is string // Descrição da ação reputacaoResultante is real // Valor final após esta ação END ``` //############################## //############################## ``` // ========== SISTEMA DE CONSENSO ========== // Interface para diferentes algoritmos de consenso Class IConsensusAlgorithm // Método para validar um bloco (cada algoritmo implementa sua lógica) PROCEDURE ValidarBloco(bloco is BlocoDocChain, chain is array of BlocoDocChain) END // Método para selecionar o próximo validador PROCEDURE SelecionarValidador(peers is array of NoPeer) END END // Implementação de Prova de Trabalho (PoW) Class ProofOfWorkConsensus EXTENDS IConsensusAlgorithm difficulty is int = 4 // Dificuldade (número de zeros iniciais) // Valida se um bloco está minerado corretamente OVERRIDE PROCEDURE ValidarBloco(bloco is BlocoDocChain, chain is array of BlocoDocChain) // Verificar se o hash do bloco começa com o número correto de zeros prefixoEsperado is string = RepeatString("0", difficulty) IF Left(bloco.hash, difficulty) <> prefixoEsperado THEN Trace("Bloco inválido: hash não atende à dificuldade estabelecida") Result False END // Recalcular o hash e verificar hashCalculado is string = CalcularHashBloco(bloco) IF bloco.hash <> hashCalculado THEN Trace("Bloco inválido: hash não corresponde ao conteúdo") Result False END // Verificar ligação com o bloco anterior IF ArrayCount(chain) > 0 THEN blocoAnterior is BlocoDocChain = chain[ArrayCount(chain)] IF bloco.previousHash <> blocoAnterior.hash THEN Trace("Bloco inválido: não está conectado ao último bloco da cadeia") Result False END END Result True END // No PoW, qualquer peer pode tentar minerar OVERRIDE PROCEDURE SelecionarValidador(peers is array of NoPeer) // Retorna todos, pois qualquer um pode competir Result peers END // Método auxiliar para calcular hash (implementado na classe DocChain) PROCEDURE CalcularHashBloco(bloco is BlocoDocChain) dados is string = [ StrToString(bloco.index) + DateTimeToString(bloco.timestamp, "yyyyMMddhhmmss") + bloco.previousHash + bloco.documentosHash + StrToString(bloco.nonce) ] Result HashString(HASH_SHA256, dados) END END // Implementação de Prova de Participação (PoS) Class ProofOfStakeConsensus EXTENDS IConsensusAlgorithm reputacaoManager is SistemaReputacao // Sistema de reputação // No PoS, não precisamos da prova de trabalho, apenas verificar a autenticidade OVERRIDE PROCEDURE ValidarBloco(bloco is BlocoDocChain, chain is array of BlocoDocChain) // Verificar assinatura do validador // Verificar se o validador tinha direito (stake) para criar o bloco // Verificar integridade da cadeia // Implementação simplificada para exemplo Result True END // Seleciona validador baseado na reputação (stake) OVERRIDE PROCEDURE SelecionarValidador(peers is array of NoPeer) candidatos is array of NoPeer // Filtra validadores com boa reputação FOR EACH peer OF peers IF reputacaoManager.EhConfiavel(peer.id) THEN ArrayAdd(candidatos, peer) END END // Se não houver candidatos confiáveis, usa qualquer um IF ArrayCount(candidatos) = 0 THEN candidatos = peers END // Seleciona aleatoriamente, mas ponderado pela reputação validadorSelecionado is NoPeer = SelecionarPonderado(candidatos) validadores is array of NoPeer ArrayAdd(validadores, validadorSelecionado) Result validadores END // Seleciona um peer ponderado pela reputação PRIVATE PROCEDURE SelecionarPonderado(candidatos is array of NoPeer) totalReputacao is real = 0 pesos is array of real // Calcula o total de reputação FOR EACH peer OF candidatos repPeer is real = reputacaoManager.ObterReputacao(peer.id) ArrayAdd(pesos, repPeer) totalReputacao += repPeer END // Escolhe aleatoriamente baseado no peso valorAleatorio is real = Random(0, totalReputacao) cumulativo is real = 0 FOR i = 1 TO ArrayCount(candidatos) cumulativo += pesos[i] IF valorAleatorio <= cumulativo THEN Result candidatos[i] END END // Caso de fallback (não deveria acontecer) Result candidatos[1] END END ``` //############################## //############################## ``` // ========== INTERFACE DE USUÁRIO ========== // Interface WYSIWYG baseada em componentes Window WIN_DocChainManager // Componentes de UI aqui (omitidos por brevidade) // Esta seria uma interface completa para gerenciar documentos // com abas para certificar, verificar, explorar a blockchain, etc. END // Procedimento para gerenciar documento com interface Procedure DocChainGUI() OpenMobileWindow(WIN_DocChainManager) END // API RESTful para integração externa Class DocChainAPI httpServidor is HTTPServer docChain is DocChain // Inicia o servidor HTTP PROCEDURE Iniciar(porta is int = 8080) // Configura o servidor HTTP httpServidor = new HTTPServer httpServidor.Root = "/api/docchain" httpServidor.Port = porta // Registra os endpoints REST httpServidor.AddPath("/verificar/{hash}", VerificarDocumento) httpServidor.AddPath("/documento/{id}", ObterDocumento) httpServidor.AddPath("/certificar", CertificarDocumento, httpPost) httpServidor.AddPath("/blocos", ListarBlocos) // Inicia o servidor IF httpServidor.Start() THEN Trace("API DocChain iniciada na porta " + porta) Result True ELSE Trace("Erro ao iniciar API: " + ErrorInfo()) Result False END END // Endpoint para verificar documento PRIVATE PROCEDURE VerificarDocumento(request is HTTPRequest, response is HTTPResponse) // Obtém o hash da URL hash is string = request.PathVariable["hash"] // Busca o documento na blockchain documentoEncontrado is boolean = False documentoInfo is Documento // Percorre a blockchain em busca do documento FOR EACH bloco OF docChain.chain FOR EACH doc OF bloco.documentos IF doc.hashConteudo = hash THEN documentoEncontrado = True documentoInfo = doc Break END END IF documentoEncontrado THEN Break END END // Retorna o resultado IF documentoEncontrado THEN response.ContentType = "application/json" response.StatusCode = 200 resultado is JSON resultado.encontrado = True resultado.documento = documentoInfo resultado.dataVerificacao = DateTimeToString(Now()) resultado.blocoConfirmacoes = ArrayCount(docChain.chain) - documentoInfo.index response.Content = JSONToString(resultado) ELSE response.ContentType = "application/json" response.StatusCode = 404 resultado is JSON resultado.encontrado = False resultado.mensagem = "Documento não encontrado na blockchain" response.Content = JSONToString(resultado) END END // Endpoint para obter documento PRIVATE PROCEDURE ObterDocumento(request is HTTPRequest, response is HTTPResponse) // Implementação similar ao VerificarDocumento, mas buscando por ID docId is string = request.PathVariable["id"] // Busca na blockchain... // [código omitido por brevidade] END // Endpoint para certificar documento PRIVATE PROCEDURE CertificarDocumento(request is HTTPRequest, response is HTTPResponse) // Recebe documento via POST dadosDocumento is JSON = JSONParse(request.Content) // Cria um novo documento doc is Documento doc.nome = dadosDocumento.nome doc.hashConteudo = dadosDocumento.hash doc.marcaTemporal = Now() doc.proprietario = dadosDocumento.proprietario doc.categoria = dadosDocumento.categoria doc.metadados = dadosDocumento.metadados // Assina o documento docChain.AssinaDocumento(doc) // Adiciona à lista de pendentes IF docChain.AdicionarDocumentoPendente(doc) THEN response.ContentType = "application/json" response.StatusCode = 201 resultado is JSON resultado.sucesso = True resultado.mensagem = "Documento adicionado à fila para certificação" resultado.documentoId = doc.id response.Content = JSONToString(resultado) ELSE response.ContentType = "application/json" response.StatusCode = 400 resultado is JSON resultado.sucesso = False resultado.mensagem = "Erro ao adicionar documento" response.Content = JSONToString(resultado) END END // Endpoint para listar blocos PRIVATE PROCEDURE ListarBlocos(request is HTTPRequest, response is HTTPResponse) // Implementação para listar blocos da blockchain // [código omitido por brevidade] END END ``` //############################## //############################## ``` // ========== APLICAÇÃO COMPLETA ========== // Inicia o sistema completo DocChain P2P Procedure IniciarDocChainP2P() // Inicializa a blockchain docChain is DocChain // Inicializa o sistema de reputação reputacao is SistemaReputacao // Inicializa o algoritmo de consenso (configura para PoW ou PoS) // Por padrão, usamos PoW para teste, mas pode ser configurado consenso is IConsensusAlgorithm = new ProofOfWorkConsensus() // Configura o nó P2P docChain.peersManager.nome = "DocChain Node " + DateTimeToString(Now(), "yyyyMMdd-hhmmss") // Inicia o serviço P2P porta is int = ExtrairPortaDaConfig() docChain.peersManager.Iniciar(porta) // Inicia a API REST para acesso externo api is DocChainAPI api.docChain = docChain api.Iniciar(8080) // Conecta a nós conhecidos (seeds) ConectarSeedPeers(docChain) // Inicia o loop de mineração em background THREAD NomeProcedure = LoopMineracao(docChain) THREAD NomeProcedure.Estado = threadAtivoAguardandoFinal // Exibe informações do nó Info([ ===== DocChain P2P v1.0 ===== Nó inicializado com sucesso! ID: ~docChain.peersManager.id~ Porta P2P: ~porta~ API REST: http://localhost:8080/api/docchain Chave pública: ~Left(docChain.carteira.chavePublica, 20)~... Modo de consenso: ~TypeName(consenso)~ Blockchain iniciada com ~ArrayCount(docChain.chain)~ bloco(s) Sistema pronto para uso! ]) // Abre a interface gráfica para interagir com o sistema DocChainGUI() END // Obtém a porta da configuração ou usa o padrão Procedure ExtrairPortaDaConfig() // Lê arquivo de configuração IF fFileExist("docchain.config") THEN config is JSON = JSONParse(fLoadText("docchain.config")) IF config.porta <> Null THEN Result config.porta END END // Porta padrão Result 8785 END // Conecta aos nós seed conhecidos Procedure ConectarSeedPeers(docChain is DocChain) // Lista de nós seed para bootstrap inicial seeds is array of strings = ["seed1.docchain.exemplo:8785", "seed2.docchain.exemplo:8785"] // Adiciona seeds de arquivo de configuração IF fFileExist("peers.list") THEN linhas is string = fLoadText("peers.list") seedsArquivo is array of strings = Split(linhas, CR) FOR EACH seed OF seedsArquivo IF seed <> "" THEN ArrayAdd(seeds, seed) END END END // Tenta conectar a cada seed FOR EACH seed OF seeds docChain.peersManager.ConectarAoPeer(seed) END END // Loop de mineração em background Procedure LoopMineracao(docChain is DocChain) WHILE True // Verifica se há documentos pendentes para minerar IF ArrayCount(docChain.documentosPendentes) > 0 THEN Trace("Iniciando mineração de " + ArrayCount(docChain.documentosPendentes) + " documento(s) pendente(s)") docChain.MinerarBloco() END // Aguarda um tempo antes de tentar novamente Delay(10000) // 10 segundos END END // Procedure de demonstração da aplicação completa Procedure DemonstracaoDocChain() // Cria arquivo de teste para certificação testeDir is string = fCurrentDir() + "\teste" IF fMakeDir(testeDir) = False AND fDirExist(testeDir) = False THEN Trace("Erro ao criar diretório de teste") Return END testeArquivo is string = testeDir + "\contrato_teste.pdf" fSaveText(testeArquivo, "Este é um documento de teste para certificação na blockchain") // Inicializa a blockchain docChain is DocChain // Certifica o documento doc1 is Documento = docChain.CriarDocumento(testeArquivo, "contrato", "{'cliente': 'Empresa Demo', 'valor': 50000}") // Minera o bloco docChain.MinerarBloco() // Verifica a blockchain docChain.VerificarBlockchain() // Exibe o hash do documento para posterior verificação Info([ === Demonstração DocChain Concluída === Documento certificado com sucesso: Nome: ~doc1.nome~ Hash: ~doc1.hashConteudo~ Este hash pode ser usado para verificar o documento posteriormente. Documento incluído no bloco #~docChain.chain[ArrayCount(docChain.chain)].index~ ]) END ``` //############################## Este sistema, DocChain P2P, é uma implementação inovadora que combina: 1. **Blockchain para Documentos**: Permite certificar, validar e verificar documentos de forma descentralizada 2. **Rede Peer-to-Peer**: Implementada com WebSockets do WLanguage para comunicação direta entre nós 3. **Mecanismos de Consenso Flexíveis**: Suporta diferentes algoritmos (Prova de Trabalho e Prova de Participação) 4. **Criptografia Avançada**: Usa as funções robustas do WLanguage para assinaturas digitais e hashing 5. **Sistema de Reputação**: Mantém um registro da confiabilidade dos validadores na rede 6. **Integração com IPFS**: Permite armazenamento distribuído dos documentos físicos (não apenas seus hashes) 7. **API RESTful**: Possibilita integração com sistemas externos 8. **Detecção de Fraudes com IA**: Usa o novo recurso AIExecute() do WX 28 para análise inteligente de documentos Este sistema é totalmente implementado em WLanguage puro, aproveitando recursos de multithreading, WebSockets, criptografia e estruturas orientadas a objetos. Ele poderia ser usado em cenários reais como: - Cartórios digitais descentralizados - Validação de diplomas e certificados acadêmicos - Contratos inteligentes com validação de múltiplas partes - Sistemas de rastreabilidade de documentos para compliance A implementação é muito mais elegante e concisa que seria em Python ou outras linguagens, graças às funções nativas do WLanguage para operações criptográficas e gerenciamento de rede. Como usar: ``` // Para iniciar o sistema completo: IniciarDocChainP2P() // Para executar apenas uma demonstração: DemonstracaoDocChain() ``` Bons estudos -- Adriano José Boller ______________________________________________ Consultor e Representante Oficial da PcSoft no Brasil +55 (41) 99949 1800 adrianoboller@gmail.com skype: adrianobollerhttp://wxinformatica.com.br/
Membre enregistré 3 851 messages
Posté le 01 avril 2025 - 16:33
Bom dia! Vou criar um exemplo inovador de rede peer-to-peer usando sockets em WLanguage. Preparei um sistema de compartilhamento de recursos distribuído com descoberta automática de peers na rede local, que vou chamar de **WNetShare** - uma solução P2P para compartilhamento de recursos entre dispositivos com WX. //############################## ``` // WNetShare: Sistema P2P de compartilhamento e colaboração distribuída // Versão 1.0 - Criado por Adriano // ========== ESTRUTURAS BÁSICAS ========== // Classe para gerenciar um Peer na rede P2P Class Peer id is string = GetUUID() // Identificador único do peer nome is string // Nome amigável do peer endereco is string // Endereço IP:Porta recursos is array of Recurso // Recursos compartilhados por este peer ultimoContato is datetime // Último contato com este peer status is int = PEER_STATUS_DESCONHECIDO // Status do peer socket is Socket // Socket de comunicação com este peer CONSTANT PEER_STATUS_DESCONHECIDO = 0 CONSTANT PEER_STATUS_CONECTADO = 1 CONSTANT PEER_STATUS_DESCONECTADO = 2 CONSTANT PEER_STATUS_OCUPADO = 3 CONSTRUCTOR(novo_nome is string, novo_endereco is string) nome = novo_nome endereco = novo_endereco ultimoContato = Now() END END // Define um recurso compartilhado na rede Class Recurso id is string = GetUUID() // Identificador único do recurso nome is string // Nome do recurso tipo is int // Tipo do recurso (arquivo, processamento, etc) metadados is string // Metadados em JSON proprietarioId is string // ID do peer que compartilha o recurso disponivel is boolean = True // Disponibilidade atual do recurso hash is string // Hash para verificação de integridade // Constantes para tipos de recursos CONSTANT TIPO_ARQUIVO = 1 // Compartilhamento de arquivo CONSTANT TIPO_PROCESSAMENTO = 2 // Capacidade de processamento CONSTANT TIPO_ARMAZENAMENTO = 3 // Espaço de armazenamento CONSTANT TIPO_IMPRESSAO = 4 // Serviço de impressão CONSTANT TIPO_DADOS = 5 // Conjunto de dados estruturados END // Gerenciador da rede P2P Class WNetShareManager // Informações deste nó idLocal is string = GetUUID() // ID deste nó nomeLocal is string // Nome deste nó // Lista de peers conhecidos peers is array of Peer // Lista de peers conhecidos // Recursos disponíveis recursosLocais is array of Recurso // Recursos compartilhados por este nó recursosRede is array of Recurso // Cache de recursos disponíveis na rede // Comunicação portaEscuta is int = 13579 // Porta para escuta de conexões socketServidor is Socket // Socket do servidor socketThreadAtiva is boolean = False // Estado da thread de escuta // Descoberta ultimaDescoberta is datetime // Última vez que executou descoberta intervaloDescoberta is int = 30 // Intervalo de descoberta em segundos // Configuração CONSTRUCTOR(nome is string, porta is int = 13579) nomeLocal = nome portaEscuta = porta END // Inicia o serviço P2P PROCEDURE Iniciar() // Inicializa o servidor socketServidor = new Socket // Cria um socket TCP IF socketServidor.Create(SocketIP, portaEscuta) = False THEN Trace("Erro ao iniciar servidor na porta " + portaEscuta + ": " + ErrorInfo()) Result False END // Inicia thread para aceitar conexões socketThreadAtiva = True ThreadExecute(AceitarConexoes, threadNormal) // Anuncia presença na rede (broadcast) AnunciarPresenca() // Inicia a descoberta de peers na rede ThreadExecute(DescobrirPeers, threadNormal) Info("WNetShare iniciado com sucesso na porta " + portaEscuta) Info("ID do nó: " + idLocal) Info("Nome do nó: " + nomeLocal) Result True END // Thread que aceita novas conexões THREAD PROCEDURE AceitarConexoes() WHILE socketThreadAtiva // Aguarda por novas conexões novaSock is Socket Trace("Aguardando novas conexões...") novaSock = socketServidor.WaitConnection() IF novaSock..Valid THEN Trace("Nova conexão recebida de: " + novaSock..RemoteAddress) // Inicia thread para processar esta conexão ThreadExecute(ProcessarConexao, threadNormal, novaSock) END // Pequena pausa para não consumir muito CPU Delay(50) END END // Processa uma nova conexão THREAD PROCEDURE ProcessarConexao(socket is Socket) // Primeiro, recebe a mensagem de apresentação msgHello is Buffer = socket.Receive(5000) // Timeout de 5 segundos IF socket..TIMEOUT THEN Trace("Timeout ao receber cumprimento inicial") socket.Close() RETURN END // Decodifica a mensagem JSON TRY msg is JSON = JSONParse(msgHello) IF msg.tipo = "HELLO" THEN // Extrai informações do peer peerId is string = msg.id peerNome is string = msg.nome peerEndereco is string = socket..RemoteAddress + ":" + msg.porta // Registra ou atualiza o peer ProcessarRegistroPeer(peerId, peerNome, peerEndereco, socket) // Responde ao cumprimento EnviarMensagemHello(socket) // Processa mensagens deste peer ProcessarMensagensPeer(socket, peerId) ELSE Trace("Mensagem inicial inválida") socket.Close() END CATCH Trace("Erro ao processar mensagem: " + ErrorInfo()) socket.Close() END END // Processa o registro/atualização de um peer PROCEDURE ProcessarRegistroPeer(id is string, nome is string, endereco is string, socket is Socket) // Verifica se já conhecemos este peer peerExistente is boolean = False FOR i = 1 TO ArrayCount(peers) IF peers[i].id = id THEN // Atualiza as informações do peer peers[i].nome = nome peers[i].endereco = endereco peers[i].ultimoContato = Now() peers[i].status = Peer.PEER_STATUS_CONECTADO peers[i].socket = socket peerExistente = True Trace("Peer atualizado: " + nome + " (" + endereco + ")") Break END END // Se não existe, adiciona à lista IF peerExistente = False THEN novoPeer is Peer(nome, endereco) novoPeer.id = id novoPeer.status = Peer.PEER_STATUS_CONECTADO novoPeer.socket = socket ArrayAdd(peers, novoPeer) Trace("Novo peer adicionado: " + nome + " (" + endereco + ")") // Solicita lista de recursos deste peer SolicitarRecursos(novoPeer) END END // Envia mensagem de hello para um socket PROCEDURE EnviarMensagemHello(socket is Socket) msg is JSON msg.tipo = "HELLO" msg.id = idLocal msg.nome = nomeLocal msg.porta = portaEscuta msg.versao = "1.0" jsonMsg is string = JSONToString(msg) socket.Send(jsonMsg) END // Solicita recursos disponíveis de um peer PROCEDURE SolicitarRecursos(peer is Peer) msg is JSON msg.tipo = "GET_RECURSOS" msg.solicitante = idLocal jsonMsg is string = JSONToString(msg) peer.socket.Send(jsonMsg) END // Loop principal para processar mensagens de um peer PROCEDURE ProcessarMensagensPeer(socket is Socket, peerId is string) WHILE socket..Estado = socketConectado // Recebe próxima mensagem mensagem is Buffer = socket.Receive(0) // 0 = bloqueante IF socket..Estado <> socketConectado THEN // Socket fechado ou erro Break END // Processa a mensagem IF mensagem <> "" THEN ProcessarMensagem(mensagem, peerId, socket) END // Pequena pausa para não consumir muito CPU Delay(10) END // Atualiza status do peer FOR i = 1 TO ArrayCount(peers) IF peers[i].id = peerId THEN peers[i].status = Peer.PEER_STATUS_DESCONECTADO peers[i].socket = Null Trace("Peer desconectado: " + peers[i].nome) Break END END END // Processa uma mensagem recebida PROCEDURE ProcessarMensagem(mensagem is Buffer, peerId is string, socket is Socket) TRY msg is JSON = JSONParse(mensagem) SWITCH msg.tipo CASE "GET_RECURSOS": // Envia lista de recursos locais EnviarRecursosLocais(socket) CASE "RECURSOS": // Atualiza a lista de recursos do peer AtualizarRecursosPeer(peerId, msg.recursos) CASE "SOLICITAR_RECURSO": // Processa solicitação de um recurso específico ProcessarSolicitacaoRecurso(msg.recursoId, msg.solicitante, socket) CASE "TRANSFERENCIA_ARQUIVO": // Inicia recebimento de arquivo ProcessarTransferenciaArquivo(msg, socket) CASE "BUSCAR": // Processa solicitação de busca ResultadoBusca(msg.termo, socket) CASE "PING": // Responde ping com pong EnviarPong(socket) CASE "PEER_LIST": // Recebeu lista de peers conhecidos ProcessarListaPeers(msg.peers) END CATCH Trace("Erro ao processar mensagem: " + ErrorInfo()) END END // Envia lista de recursos locais PROCEDURE EnviarRecursosLocais(socket is Socket) msg is JSON msg.tipo = "RECURSOS" msg.recursos = recursosLocais jsonMsg is string = JSONToString(msg) socket.Send(jsonMsg) END // Atualiza a lista de recursos de um peer PROCEDURE AtualizarRecursosPeer(peerId is string, recursos is array of Recurso) // Primeiro remove os recursos antigos deste peer FOR i = ArrayCount(recursosRede) DOWNTO 1 IF recursosRede[i].proprietarioId = peerId THEN ArrayDelete(recursosRede, i) END END // Adiciona os novos recursos FOR EACH recurso OF recursos recurso.proprietarioId = peerId ArrayAdd(recursosRede, recurso) END Trace("Recursos atualizados para peer " + peerId + ": " + ArrayCount(recursos) + " recursos") END // Anuncia presença na rede (broadcast UDP) PROCEDURE AnunciarPresenca() // Utiliza UDP broadcast para anunciar presença sockBroadcast is Socket // Cria socket UDP IF sockBroadcast.Create(SocketDgram) = False THEN Trace("Erro ao criar socket de broadcast: " + ErrorInfo()) RETURN END // Habilita broadcast sockBroadcast.Option(sockBroadcast, True) // Prepara mensagem de anúncio msg is JSON msg.tipo = "ANUNCIO" msg.id = idLocal msg.nome = nomeLocal msg.porta = portaEscuta jsonMsg is string = JSONToString(msg) // Envia para endereço de broadcast enderecosBroadcast is array of strings = ["255.255.255.255:13580", "224.0.0.1:13580"] FOR EACH endereco OF enderecosBroadcast sockBroadcast.SendTo(jsonMsg, endereco) END sockBroadcast.Close() Trace("Anúncio de presença enviado para a rede") END // Thread para descoberta periódica de peers THREAD PROCEDURE DescobrirPeers() // Socket para escutar anúncios sockEscuta is Socket // Cria socket UDP para escutar anúncios IF sockEscuta.Create(SocketDgram, 13580) = False THEN Trace("Erro ao criar socket de descoberta: " + ErrorInfo()) RETURN END // Loop de descoberta WHILE socketThreadAtiva // Verifica se é hora de anunciar presença novamente IF DateDifference(ultimaDescoberta, Now(), dtSecond) > intervaloDescoberta THEN AnunciarPresenca() ultimaDescoberta = Now() END // Verifica se há anúncios IF sockEscuta.WaitForData(1000) THEN // Timeout 1 segundo mensagem is Buffer endereco is string // Recebe mensagem e endereço de origem sockEscuta.ReceiveFrom(mensagem, endereco, 2000) // Processa o anúncio IF mensagem <> "" THEN ProcessarAnuncio(mensagem, endereco) END END // Atualiza status dos peers AtualizarStatusPeers() // Pequena pausa Delay(100) END // Fecha socket ao terminar sockEscuta.Close() END // Processa anúncio de peer PROCEDURE ProcessarAnuncio(mensagem is Buffer, endereco is string) TRY msg is JSON = JSONParse(mensagem) IF msg.tipo = "ANUNCIO" AND msg.id <> idLocal THEN Trace("Recebido anúncio de: " + msg.nome + " (" + endereco + ")") // Extrai endereço IP e porta do anúncio partes is array of strings = Split(endereco, ":") enderecoIP is string = partes[1] // Constrói endereço com a porta de escuta do peer enderecoPeer is string = enderecoIP + ":" + msg.porta // Verifica se já conhecemos este peer peerConhecido is boolean = False FOR i = 1 TO ArrayCount(peers) IF peers[i].id = msg.id THEN peerConhecido = True peers[i].ultimoContato = Now() // Se estiver desconectado, tenta reconectar IF peers[i].status = Peer.PEER_STATUS_DESCONECTADO THEN ConectarAoPeer(enderecoPeer, msg.id) END Break END END // Se não conhecemos, tenta conectar IF peerConhecido = False THEN ConectarAoPeer(enderecoPeer, msg.id) END END CATCH Trace("Erro ao processar anúncio: " + ErrorInfo()) END END // Conecta a um peer específico PROCEDURE ConectarAoPeer(endereco is string, peerIdEsperado is string = "") Trace("Tentando conectar a peer: " + endereco) // Cria socket cliente sockCliente is Socket // Cria o socket TCP IF sockCliente.Create(SocketIP) = False THEN Trace("Erro ao criar socket cliente: " + ErrorInfo()) Result False END // Tenta conectar IF sockCliente.Connect(endereco, 5000) = False THEN // Timeout 5 segundos Trace("Falha ao conectar a " + endereco + ": " + ErrorInfo()) sockCliente.Close() Result False END // Envia mensagem de apresentação EnviarMensagemHello(sockCliente) // Aguarda resposta mensagem is Buffer = sockCliente.Receive(5000) // Timeout de 5 segundos IF sockCliente..TIMEOUT OR mensagem = "" THEN Trace("Timeout ao aguardar resposta do peer") sockCliente.Close() Result False END // Processa a resposta TRY msg is JSON = JSONParse(mensagem) IF msg.tipo = "HELLO" THEN peerId is string = msg.id peerNome is string = msg.nome // Verifica se o ID confere com o esperado (se fornecido) IF peerIdEsperado <> "" AND peerId <> peerIdEsperado THEN Trace("ID do peer não confere com o esperado") sockCliente.Close() Result False END // Registra o peer ProcessarRegistroPeer(peerId, peerNome, endereco, sockCliente) // Processa mensagens em nova thread ThreadExecute(ProcessarMensagensPeer, threadNormal, sockCliente, peerId) Trace("Conectado com sucesso ao peer " + peerNome) Result True ELSE Trace("Resposta inválida do peer") sockCliente.Close() Result False END CATCH Trace("Erro ao processar resposta: " + ErrorInfo()) sockCliente.Close() Result False END END // Atualiza o status dos peers baseado no último contato PROCEDURE AtualizarStatusPeers() FOR i = 1 TO ArrayCount(peers) // Se último contato foi há mais de 5 minutos, marca como desconectado IF DateDifference(peers[i].ultimoContato, Now(), dtMinute) > 5 AND peers[i].status = Peer.PEER_STATUS_CONECTADO THEN peers[i].status = Peer.PEER_STATUS_DESCONECTADO // Fecha o socket se ainda estiver aberto IF peers[i].socket..Valid THEN peers[i].socket.Close() peers[i].socket = Null END END END END // Compartilha um arquivo na rede PROCEDURE CompartilharArquivo(caminhoArquivo is string, nome is string = "", descricao is string = "") // Verifica se o arquivo existe IF fFileExist(caminhoArquivo) = False THEN Trace("Arquivo não encontrado: " + caminhoArquivo) Result False END // Se nome não foi fornecido, usa o nome do arquivo IF nome = "" THEN nome = fExtractPath(caminhoArquivo, fFileName + fExtension) END // Calcular hash do arquivo para verificação de integridade conteudo is Buffer = fLoadBuffer(caminhoArquivo) hashArquivo is string = HashString(HASH_SHA256, conteudo) // Cria novo recurso novoRecurso is Recurso novoRecurso.nome = nome novoRecurso.tipo = Recurso.TIPO_ARQUIVO novoRecurso.proprietarioId = idLocal novoRecurso.hash = hashArquivo // Prepara metadados metadados is JSON metadados.caminho = caminhoArquivo metadados.tamanho = fSizeFile(caminhoArquivo) metadados.descricao = descricao metadados.dataModificacao = DateSys() + TimeSys() novoRecurso.metadados = JSONToString(metadados) // Adiciona à lista de recursos locais ArrayAdd(recursosLocais, novoRecurso) // Notifica peers sobre novo recurso NotificarNovoRecurso(novoRecurso) Trace("Arquivo compartilhado: " + nome) Result True END // Notifica os peers sobre um novo recurso PROCEDURE NotificarNovoRecurso(recurso is Recurso) msg is JSON msg.tipo = "NOVO_RECURSO" msg.recurso = recurso jsonMsg is string = JSONToString(msg) // Envia para todos os peers conectados FOR i = 1 TO ArrayCount(peers) IF peers[i].status = Peer.PEER_STATUS_CONECTADO THEN peers[i].socket.Send(jsonMsg) END END END // Processa solicitação de recurso PROCEDURE ProcessarSolicitacaoRecurso(recursoId is string, solicitanteId is string, socket is Socket) // Procura o recurso solicitado recursoEncontrado is boolean = False recursoSolicitado is Recurso FOR i = 1 TO ArrayCount(recursosLocais) IF recursosLocais[i].id = recursoId THEN recursoEncontrado = True recursoSolicitado = recursosLocais[i] Break END END // Se não encontrou, informa erro IF recursoEncontrado = False THEN msg is JSON msg.tipo = "ERRO" msg.codigo = 404 msg.mensagem = "Recurso não encontrado" socket.Send(JSONToString(msg)) RETURN END // Verifica se o recurso está disponível IF recursoSolicitado.disponivel = False THEN msg is JSON msg.tipo = "ERRO" msg.codigo = 503 msg.mensagem = "Recurso temporariamente indisponível" socket.Send(JSONToString(msg)) RETURN END // Processa de acordo com o tipo do recurso SWITCH recursoSolicitado.tipo CASE Recurso.TIPO_ARQUIVO: // Inicia transferência de arquivo IniciarTransferenciaArquivo(recursoSolicitado, socket) CASE Recurso.TIPO_PROCESSAMENTO: // Inicia serviço de processamento IniciarProcessamento(recursoSolicitado, socket, solicitanteId) CASE Recurso.TIPO_ARMAZENAMENTO: // Prepara para receber dados a serem armazenados PrepararArmazenamento(recursoSolicitado, socket, solicitanteId) // Outros tipos de recursos... END END // Inicia transferência de arquivo PROCEDURE IniciarTransferenciaArquivo(recurso is Recurso, socket is Socket) // Obtém caminho do arquivo dos metadados metadados is JSON = JSONParse(recurso.metadados) caminhoArquivo is string = metadados.caminho // Verifica se o arquivo ainda existe IF fFileExist(caminhoArquivo) = False THEN msg is JSON msg.tipo = "ERRO" msg.codigo = 404 msg.mensagem = "Arquivo não encontrado no sistema" socket.Send(JSONToString(msg)) // Marca recurso como indisponível FOR i = 1 TO ArrayCount(recursosLocais) IF recursosLocais[i].id = recurso.id THEN recursosLocais[i].disponivel = False Break END END RETURN END // Prepara mensagem de início de transferência msg is JSON msg.tipo = "TRANSFERENCIA_ARQUIVO" msg.recursoId = recurso.id msg.nome = recurso.nome msg.tamanho = fSizeFile(caminhoArquivo) msg.hash = recurso.hash // Envia informações sobre o arquivo socket.Send(JSONToString(msg)) // Aguarda confirmação do cliente resposta is Buffer = socket.Receive(10000) // Timeout 10 segundos IF resposta = "" OR socket..TIMEOUT THEN Trace("Timeout aguardando confirmação para transferência") RETURN END // Verifica confirmação TRY confMsg is JSON = JSONParse(resposta) IF confMsg.tipo = "CONFIRMAR_TRANSFERENCIA" AND confMsg.recursoId = recurso.id THEN // Inicia transferência em blocos EnviarArquivoEmBlocos(caminhoArquivo, socket) ELSE Trace("Resposta inválida para transferência de arquivo") END CATCH Trace("Erro ao processar confirmação: " + ErrorInfo()) END END // Envia arquivo em blocos PROCEDURE EnviarArquivoEmBlocos(caminhoArquivo is string, socket is Socket) // Tamanho de cada bloco (1MB) tamanhoBloco is int = 1024 * 1024 // Abre o arquivo arquivoId is int = fOpen(caminhoArquivo, foRead) IF arquivoId = -1 THEN Trace("Erro ao abrir arquivo: " + ErrorInfo()) RETURN END tamanhoArquivo is int = fSizeFile(caminhoArquivo) blocoAtual is int = 1 totalBlocos is int = (tamanhoArquivo / tamanhoBloco) + 1 // Lê e envia o arquivo em blocos WHILE NOT fEOF(arquivoId) // Lê um bloco bloco is Buffer = fReadBufferBlock(arquivoId, tamanhoBloco) // Prepara cabeçalho do bloco cabecalho is JSON cabecalho.tipo = "BLOCO_ARQUIVO" cabecalho.numero = blocoAtual cabecalho.total = totalBlocos cabecalho.tamanho = Length(bloco) cabecalho.final = fEOF(arquivoId) // Concatena cabeçalho e dados socket.Send(JSONToString(cabecalho) + CR + bloco) // Aguarda confirmação para próximo bloco (flow control) confBloco is Buffer = socket.Receive(30000) // 30 segundos timeout IF confBloco = "" OR socket..TIMEOUT THEN Trace("Timeout aguardando confirmação de bloco") fClose(arquivoId) RETURN END // Próximo bloco blocoAtual++ // Mostra progresso IF blocoAtual % 10 = 0 OR blocoAtual = totalBlocos THEN Trace("Enviando arquivo: " + blocoAtual + "/" + totalBlocos + " blocos") END END // Fecha o arquivo fClose(arquivoId) Trace("Transferência de arquivo concluída") END // Inicia um serviço de processamento distribuído PROCEDURE IniciarProcessamento(recurso is Recurso, socket is Socket, solicitanteId is string) // Este é um exemplo de processamento simples // Em um sistema real, poderia executar tarefas complexas // Obtém detalhes da tarefa metadados is JSON = JSONParse(recurso.metadados) nomeFuncao is string = metadados.funcao // Prepara resposta msg is JSON msg.tipo = "INICIAR_PROCESSAMENTO" msg.recursoId = recurso.id msg.funcao = nomeFuncao // Envia início de processamento socket.Send(JSONToString(msg)) // Aguarda os dados para processamento dadosIn is Buffer = socket.Receive(30000) // 30 segundos timeout IF dadosIn = "" OR socket..TIMEOUT THEN Trace("Timeout aguardando dados para processamento") RETURN END // Processa os dados de acordo com a função solicitada TRY // Decodifica os dados de entrada dados is JSON = JSONParse(dadosIn) IF dados.tipo = "DADOS_PROCESSAMENTO" THEN // Executa o processamento de acordo com a função solicitada resultado is string = ExecutarProcessamento(nomeFuncao, dados.parametros) // Envia resultado respostaProc is JSON respostaProc.tipo = "RESULTADO_PROCESSAMENTO" respostaProc.recursoId = recurso.id respostaProc.resultado = resultado socket.Send(JSONToString(respostaProc)) ELSE Trace("Dados inválidos para processamento") END CATCH Continuando a implementação do sistema WNetShare peer-to-peer com WLanguage: //############################## ``` // Continuação do método IniciarProcessamento... Trace("Erro ao processar dados: " + ErrorInfo()) // Envia erro erroProc is JSON erroProc.tipo = "ERRO" erroProc.codigo = 500 erroProc.mensagem = "Erro ao processar dados: " + ErrorInfo() socket.Send(JSONToString(erroProc)) END END // Executa o processamento de acordo com a função solicitada PROCEDURE ExecutarProcessamento(funcao is string, parametros is JSON) SWITCH funcao CASE "CALCULAR_HASH": // Calcula hash de dados dados is string = parametros.dados tipoHash is string = parametros.tipo // SHA256, MD5, etc. IF tipoHash = "SHA256" THEN Result HashString(HASH_SHA256, dados) ELSE IF tipoHash = "MD5" THEN Result HashString(HASH_MD5, dados) ELSE Result HashString(HASH_SHA256, dados) // Default END CASE "CRIPTOGRAFAR": // Criptografa dados dados is string = parametros.dados senha is string = parametros.senha Result Crypt(dados, senha, cryptStandard, "") CASE "DESCRIPTOGRAFAR": // Descriptografa dados dados is string = parametros.dados senha is string = parametros.senha Result Decrypt(dados, senha, cryptStandard, "") CASE "COMPRIMIR": // Comprime dados dados is string = parametros.dados Result Compress(dados, compressDeflate) CASE "DESCOMPRIMIR": // Descomprime dados dados is string = parametros.dados Result Uncompress(dados, compressDeflate) CASE "CONVERTER_JSON_CSV": // Converte JSON para CSV dadosJSON is JSON = parametros.json Result JSONToCSV(dadosJSON) DEFAULT: // Função desconhecida Result "ERRO: Função de processamento desconhecida" END END // Prepara para receber dados para armazenamento PROCEDURE PrepararArmazenamento(recurso is Recurso, socket is Socket, solicitanteId is string) // Obtém detalhes do armazenamento metadados is JSON = JSONParse(recurso.metadados) // Verifica espaço disponível espacoDisponivel is int = metadados.capacidade // Prepara mensagem de confirmação msg is JSON msg.tipo = "ARMAZENAMENTO_PRONTO" msg.recursoId = recurso.id msg.espacoDisponivel = espacoDisponivel socket.Send(JSONToString(msg)) // Aguarda os dados a serem armazenados // Este é um esqueleto - implementação real precisaria de mais lógica END // Realiza uma busca na rede por recursos PROCEDURE BuscarRecursos(termo is string) // Primeiro, busca localmente resultadosLocais is array of Recurso FOR EACH recurso OF recursosLocais IF StrFind(recurso.nome, termo, IgnoreCase) > 0 OR StrFind(recurso.metadados, termo, IgnoreCase) > 0 THEN ArrayAdd(resultadosLocais, recurso) END END // Busca nos recursos conhecidos da rede resultadosRede is array of Recurso FOR EACH recurso OF recursosRede IF StrFind(recurso.nome, termo, IgnoreCase) > 0 OR StrFind(recurso.metadados, termo, IgnoreCase) > 0 THEN ArrayAdd(resultadosRede, recurso) END END // Envia solicitação de busca para todos os peers EnviarSolicitacaoBusca(termo) // Retorna os resultados já encontrados resultados is array of Recurso resultados = resultadosLocais + resultadosRede Result resultados END // Envia solicitação de busca para todos os peers PROCEDURE EnviarSolicitacaoBusca(termo is string) msg is JSON msg.tipo = "BUSCAR" msg.termo = termo msg.solicitante = idLocal jsonMsg is string = JSONToString(msg) // Envia para todos os peers conectados FOR i = 1 TO ArrayCount(peers) IF peers[i].status = Peer.PEER_STATUS_CONECTADO THEN peers[i].socket.Send(jsonMsg) END END END // Processa resultado de busca PROCEDURE ResultadoBusca(termo is string, socket is Socket) // Realiza busca local resultados is array of Recurso FOR EACH recurso OF recursosLocais IF StrFind(recurso.nome, termo, IgnoreCase) > 0 OR StrFind(recurso.metadados, termo, IgnoreCase) > 0 THEN ArrayAdd(resultados, recurso) END END // Envia resultados msg is JSON msg.tipo = "RESULTADO_BUSCA" msg.recursos = resultados socket.Send(JSONToString(msg)) END // Processa resposta de transferência de arquivo PROCEDURE ProcessarTransferenciaArquivo(msg is JSON, socket is Socket) // Este método seria implementado para o lado do cliente // que está recebendo um arquivo Trace("Recebendo arquivo: " + msg.nome + " (" + msg.tamanho + " bytes)") // Prepara para receber o arquivo diretorioDownload is string = fCurrentDir() + "\Downloads\" // Cria diretório se não existir IF fDirExist(diretorioDownload) = False THEN fMakeDir(diretorioDownload) END caminhoDestino is string = diretorioDownload + msg.nome // Confirma que está pronto para receber confirmacao is JSON confirmacao.tipo = "CONFIRMAR_TRANSFERENCIA" confirmacao.recursoId = msg.recursoId socket.Send(JSONToString(confirmacao)) // Recebe o arquivo em blocos arqDestino is int = fCreate(caminhoDestino) IF arqDestino = -1 THEN Trace("Erro ao criar arquivo de destino: " + ErrorInfo()) RETURN END totalBlocos is int = 0 blocoAtual is int = 0 transferenciaConcluida is boolean = False // Loop para receber blocos WHILE transferenciaConcluida = False // Recebe cabeçalho do bloco + dados dadosBloco is Buffer = socket.Receive(60000) // 60 segundos timeout IF dadosBloco = "" OR socket..TIMEOUT THEN Trace("Timeout recebendo bloco") fClose(arqDestino) RETURN END // Separa cabeçalho e dados posicaoCR is int = Position(dadosBloco, CR) IF posicaoCR > 0 THEN cabecalhoStr is string = Left(dadosBloco, posicaoCR - 1) dados is Buffer = Mid(dadosBloco, posicaoCR + 1) // Decodifica cabeçalho TRY cabecalho is JSON = JSONParse(cabecalhoStr) IF cabecalho.tipo = "BLOCO_ARQUIVO" THEN // Atualiza informações blocoAtual = cabecalho.numero totalBlocos = cabecalho.total // Escreve os dados no arquivo fWriteBuffer(arqDestino, dados) // Verifica se é o último bloco IF cabecalho.final = True THEN transferenciaConcluida = True END // Confirma recebimento do bloco confBloco is JSON confBloco.tipo = "CONFIRMAR_BLOCO" confBloco.numero = blocoAtual socket.Send(JSONToString(confBloco)) // Mostra progresso IF blocoAtual % 10 = 0 OR blocoAtual = totalBlocos THEN Trace("Recebendo arquivo: " + blocoAtual + "/" + totalBlocos + " blocos") END ELSE Trace("Mensagem de bloco inválida") END CATCH Trace("Erro ao processar cabeçalho do bloco: " + ErrorInfo()) END ELSE Trace("Formato de mensagem de bloco inválido") END END // Fecha o arquivo fClose(arqDestino) // Verifica a integridade do arquivo IF VerificarIntegridadeArquivo(caminhoDestino, msg.hash) = False THEN Trace("ALERTA: Hash do arquivo recebido não confere!") END Trace("Transferência concluída: " + msg.nome) END // Verifica a integridade de um arquivo pelo hash PROCEDURE VerificarIntegridadeArquivo(caminhoArquivo is string, hashEsperado is string) // Calcula o hash do arquivo recebido conteudo is Buffer = fLoadBuffer(caminhoArquivo) hashCalculado is string = HashString(HASH_SHA256, conteudo) Result (hashCalculado = hashEsperado) END // Processa lista de peers recebida PROCEDURE ProcessarListaPeers(novos_peers is array of string) // Tenta conectar a peers desconhecidos FOR EACH endereco OF novos_peers // Verifica se já conhecemos este peer peerConhecido is boolean = False FOR i = 1 TO ArrayCount(peers) IF peers[i].endereco = endereco THEN peerConhecido = True Break END END // Se não conhecemos, tenta conectar IF peerConhecido = False THEN ConectarAoPeer(endereco) END END END // Responde a um ping com pong PROCEDURE EnviarPong(socket is Socket) msg is JSON msg.tipo = "PONG" msg.timestamp = Now() socket.Send(JSONToString(msg)) END // Finaliza o sistema WNetShare PROCEDURE Finalizar() // Desconecta os peers socketThreadAtiva = False // Fecha todas as conexões FOR i = 1 TO ArrayCount(peers) IF peers[i].socket..Valid THEN peers[i].socket.Close() END END // Fecha o servidor IF socketServidor..Valid THEN socketServidor.Close() END Trace("WNetShare finalizado") END END ``` //############################## //############################## ``` // ========== CLASSES DE APLICAÇÃO ========== // Interface de chat para comunicação entre peers Class ChatP2P netShare is WNetShareManager // Gerenciador da rede P2P mensagens is array of ChatMessage // Histórico de mensagens contatos is array of Peer // Lista de contatos // Inicia o serviço de chat PROCEDURE Iniciar(gerenciador is WNetShareManager) netShare = gerenciador // Registra handlers para mensagens de chat // Em uma implementação completa, isso seria feito com eventos // Carrega contatos da base de peers RecarregarContatos() Trace("Chat P2P iniciado") Result True END // Recarrega a lista de contatos PROCEDURE RecarregarContatos() // Limpa a lista atual contatos = new array of Peer // Adiciona peers conectados como contatos FOR EACH peer OF netShare.peers IF peer.status = Peer.PEER_STATUS_CONECTADO THEN ArrayAdd(contatos, peer) END END END // Envia mensagem para um peer específico PROCEDURE EnviarMensagem(destinatarioId is string, texto is string) // Procura o peer destinatário peerEncontrado is boolean = False peerSocket is Socket FOR i = 1 TO ArrayCount(netShare.peers) IF netShare.peers[i].id = destinatarioId AND netShare.peers[i].status = Peer.PEER_STATUS_CONECTADO THEN peerEncontrado = True peerSocket = netShare.peers[i].socket Break END END // Se não encontrou ou não está conectado, retorna erro IF peerEncontrado = False OR peerSocket = Null THEN Trace("Erro: Destinatário não encontrado ou desconectado") Result False END // Prepara mensagem de chat msg is JSON msg.tipo = "CHAT_MENSAGEM" msg.remetente = netShare.idLocal msg.nomeRemetente = netShare.nomeLocal msg.texto = texto msg.timestamp = Now() // Envia a mensagem peerSocket.Send(JSONToString(msg)) // Adiciona ao histórico local novaMensagem is ChatMessage novaMensagem.remetente = netShare.idLocal novaMensagem.nomeRemetente = netShare.nomeLocal novaMensagem.destinatario = destinatarioId novaMensagem.texto = texto novaMensagem.timestamp = Now() novaMensagem.enviada = True ArrayAdd(mensagens, novaMensagem) Trace("Mensagem enviada para " + destinatarioId) Result True END // Processa uma mensagem de chat recebida PROCEDURE ProcessarMensagemRecebida(msg is JSON) // Verifica se é uma mensagem de chat IF msg.tipo <> "CHAT_MENSAGEM" THEN RETURN END // Cria objeto de mensagem novaMensagem is ChatMessage novaMensagem.remetente = msg.remetente novaMensagem.nomeRemetente = msg.nomeRemetente novaMensagem.destinatario = netShare.idLocal novaMensagem.texto = msg.texto novaMensagem.timestamp = msg.timestamp novaMensagem.enviada = False // Adiciona ao histórico ArrayAdd(mensagens, novaMensagem) // Notifica o usuário Trace("Nova mensagem de " + msg.nomeRemetente + ": " + msg.texto) // Aqui poderia chamar uma função de callback ou evento END // Obtém histórico de conversa com um contato específico PROCEDURE ObterHistoricoConversa(contatoId is string) historicoContato is array of ChatMessage FOR EACH mensagem OF mensagens IF (mensagem.remetente = contatoId AND mensagem.destinatario = netShare.idLocal) OR (mensagem.remetente = netShare.idLocal AND mensagem.destinatario = contatoId) THEN ArrayAdd(historicoContato, mensagem) END END Result historicoContato END END // Estrutura de mensagem de chat Class ChatMessage remetente is string // ID do remetente nomeRemetente is string // Nome do remetente destinatario is string // ID do destinatário texto is string // Conteúdo da mensagem timestamp is datetime // Momento do envio enviada is boolean // True se enviada, False se recebida END // Sistema de compartilhamento de streaming de áudio P2P Class AudioStreamP2P netShare is WNetShareManager // Gerenciador da rede P2P streamAtivo is boolean = False // Estado do streaming qualidade is int = 3 // Qualidade do streaming (1-5) taxaAmostragem is int = 44100 // Taxa de amostragem // Inicia um stream de áudio para um peer PROCEDURE IniciarStream(peerId is string) // Procura o peer peerEncontrado is boolean = False peerSocket is Socket FOR i = 1 TO ArrayCount(netShare.peers) IF netShare.peers[i].id = peerId AND netShare.peers[i].status = Peer.PEER_STATUS_CONECTADO THEN peerEncontrado = True peerSocket = netShare.peers[i].socket Break END END // Se não encontrou ou não está conectado, retorna erro IF peerEncontrado = False OR peerSocket = Null THEN Trace("Erro: Peer não encontrado ou desconectado") Result False END // Notifica peer sobre início de stream msg is JSON msg.tipo = "AUDIO_STREAM_INICIO" msg.remetente = netShare.idLocal msg.nomeRemetente = netShare.nomeLocal msg.qualidade = qualidade msg.taxaAmostragem = taxaAmostragem peerSocket.Send(JSONToString(msg)) // Inicia captura e envio de áudio em thread separada streamAtivo = True ThreadExecute(EnviarStreamAudio, threadNormal, peerSocket) Trace("Stream de áudio iniciado para " + peerId) Result True END // Thread que captura e envia áudio THREAD PROCEDURE EnviarStreamAudio(socket is Socket) // Inicia a captura de áudio usando recursos do WLanguage // Em uma implementação real, usaria as funções específicas de áudio // Simula captura e envio de pacotes de áudio WHILE streamAtivo AND socket..Estado = socketConectado // Simula captura de um pacote de áudio pacoteAudio is Buffer = SimularCapturaAudio() // Comprime o áudio de acordo com a qualidade audioCodificado is Buffer = ComprimirAudio(pacoteAudio, qualidade) // Prepara pacote para envio msg is JSON msg.tipo = "AUDIO_STREAM_PACOTE" msg.timestamp = Now() msg.tamanho = Length(audioCodificado) // Concatena cabeçalho e dados socket.Send(JSONToString(msg) + CR + audioCodificado) // Pequena pausa para simular captura em tempo real Delay(50) // 20 pacotes por segundo END // Notifica fim do stream msg is JSON msg.tipo = "AUDIO_STREAM_FIM" socket.Send(JSONToString(msg)) Trace("Stream de áudio encerrado") END // Simula a captura de um pacote de áudio (placeholder) PROCEDURE SimularCapturaAudio() // Em uma implementação real, usaria funções de captura de áudio // Aqui apenas geramos dados aleatórios para simular tamanhoAmostra is int = (taxaAmostragem / 20) * 2 // 50ms de áudio estéreo buffer is Buffer = BufferAllocate(tamanhoAmostra) // Gera dados aleatórios para simular áudio FOR i = 1 TO tamanhoAmostra buffer[i] = Random(0, 255) END Result buffer END // Comprime o áudio de acordo com a qualidade PROCEDURE ComprimirAudio(audio is Buffer, nivelQualidade is int) // Em uma implementação real, usaria algoritmos específicos // Aqui apenas comprimimos com função genérica para simular taxaCompressao is int = 6 - nivelQualidade // Qualidade 5 = taxa 1, Qualidade 1 = taxa 5 // Comprime o buffer audioComprimido is Buffer = Compress(audio, compressDeflate, taxaCompressao) Result audioComprimido END // Processa um pacote de áudio recebido PROCEDURE ProcessarPacoteAudio(mensagem is Buffer) // Separa cabeçalho e dados posicaoCR is int = Position(mensagem, CR) IF posicaoCR > 0 THEN cabecalhoStr is string = Left(mensagem, posicaoCR - 1) audioCodificado is Buffer = Mid(mensagem, posicaoCR + 1) // Decodifica cabeçalho TRY cabecalho is JSON = JSONParse(cabecalhoStr) IF cabecalho.tipo = "AUDIO_STREAM_PACOTE" THEN // Descomprime o áudio audioDescomprimido is Buffer = Uncompress(audioCodificado, compressDeflate) // Reproduz o áudio (placeholder) // Em uma implementação real, usaria funções de reprodução Trace("Reproduzindo pacote de áudio: " + Length(audioDescomprimido) + " bytes") // Aqui chamaria função de reprodução ELSE Trace("Mensagem de áudio inválida") END CATCH Trace("Erro ao processar pacote de áudio: " + ErrorInfo()) END ELSE Trace("Formato de pacote de áudio inválido") END END // Para o streaming de áudio PROCEDURE PararStream() streamAtivo = False Trace("Solicitado fim do stream de áudio") END END ``` //############################## //############################## ``` // ========== APLICAÇÃO PRINCIPAL ========== // Window: Interface principal do WNetShare Window WIN_WNetShare // Componentes de UI aqui (omitidos por brevidade) // Esta seria uma interface completa para gerenciar a rede P2P END // Procedimento principal que inicia o WNetShare Procedure WNetShareApp() // Obtém nome do computador para identificação nomeComputador is string = NetMachineName() // Inicia o gerenciador de rede P2P manager is WNetShareManager(nomeComputador + " (" + NetIPToString(NetIPAddress("")) + ")") IF manager.Iniciar() = False THEN Error("Erro ao iniciar WNetShare") RETURN END // Compartilha alguns recursos como exemplo compartilharExemplos(manager) // Inicia módulos adicionais chat is ChatP2P chat.Iniciar(manager) audio is AudioStreamP2P audio.netShare = manager // Abre a interface gráfica OpenMobileWindow(WIN_WNetShare, manager, chat, audio) // Ao fechar a aplicação, finaliza o WNetShare manager.Finalizar() END // Compartilha recursos de exemplo Procedure compartilharExemplos(manager is WNetShareManager) // Compartilha alguns arquivos de exemplo manager.CompartilharArquivo(fCurrentDir() + "\exemplos\documento.pdf", "Documento de Exemplo", "Documento PDF para teste do sistema P2P") // Compartilha capacidade de processamento recursoProc is Recurso recursoProc.nome = "Processamento Criptográfico" recursoProc.tipo = Recurso.TIPO_PROCESSAMENTO // Metadados com funções disponíveis metaProc is JSON metaProc.funcoes = ["CALCULAR_HASH", "CRIPTOGRAFAR", "DESCRIPTOGRAFAR"] metaProc.descricao = "Serviços de criptografia e hash" metaProc.funcao = "PROCESSAMENTO_CRIPTO" recursoProc.metadados = JSONToString(metaProc) recursoProc.proprietarioId = manager.idLocal ArrayAdd(manager.recursosLocais, recursoProc) // Compartilha espaço de armazenamento recursoArm is Recurso recursoArm.nome = "Armazenamento Temporário" recursoArm.tipo = Recurso.TIPO_ARMAZENAMENTO // Metadados do armazenamento metaArm is JSON metaArm.capacidade = 1024 * 1024 * 100 // 100 MB metaArm.duracao = "temporário" metaArm.descricao = "Espaço para armazenamento temporário de arquivos" recursoArm.metadados = JSONToString(metaArm) recursoArm.proprietarioId = manager.idLocal ArrayAdd(manager.recursosLocais, recursoArm) Trace("Recursos de exemplo compartilhados") END // Demonstração rápida do WNetShare Procedure DemonstracaoWNetShare() // Inicia dois nós P2P em portas diferentes para simular uma rede noA is WNetShareManager("Nó A") noA.portaEscuta = 13580 noA.Iniciar() noB is WNetShareManager("Nó B") noB.portaEscuta = 13581 noB.Iniciar() // Conecta B ao A Trace("Conectando nós...") enderecoA is string = "127.0.0.1:13580" noB.ConectarAoPeer(enderecoA) // Compartilha um recurso no nó A Trace("Compartilhando recurso no nó A...") // Cria arquivo de teste arquivoTeste is string = fCurrentDir() + "\teste_p2p.txt" fSaveText(arquivoTeste, "Este é um arquivo de teste para o sistema P2P WNetShare.") // Compartilha o arquivo noA.CompartilharArquivo(arquivoTeste, "Arquivo de Teste", "Arquivo para demonstração P2P") // Aguarda um pouco para a sincronização Delay(2000) // Verifica recursos disponíveis no nó B Trace("Recursos disponíveis no nó B:") FOR EACH recurso OF noB.recursosRede Trace("- " + recurso.nome + " (" + recurso.tipo + ")") END // Aqui poderia solicitar o arquivo do nó A para B // Mas isso exigiria uma implementação adicional da interface // Finaliza os nós Trace("Finalizando demonstração...") noA.Finalizar() noB.Finalizar() Trace("Demonstração concluída!") END // ==== Funções Utilitárias ==== // Converte dados JSON para formato CSV Procedure JSONToCSV(dados is JSON) csvResult is string = "" // Tenta detectar se é um array de objetos IF TypeOf(dados) = typArray THEN // Extrai nomes de colunas do primeiro objeto IF ArrayCount(dados) > 0 THEN objeto1 is JSON = dados[1] colunas is array of strings // Obtém as chaves (colunas) FOR EACH chave OF objeto1.key ArrayAdd(colunas, chave) END // Cria cabeçalho CSV FOR i = 1 TO ArrayCount(colunas) IF i > 1 THEN csvResult += "," csvResult += colunas[i] END csvResult += CR // Processa cada objeto do array FOR EACH objeto OF dados linha is string = "" FOR i = 1 TO ArrayCount(colunas) IF i > 1 THEN linha += "," // Formata o valor adequadamente valor is variant = objeto[colunas[i]] IF valor = Null THEN linha += "" ELSE IF TypeOf(valor) = typString THEN // Escape aspas e adiciona aspas em volta valorStr is string = Replace(valor, """", """""") linha += """" + valorStr + """" ELSE linha += valor END END csvResult += linha + CR END END ELSE // Para um objeto único, formato simples de chave,valor FOR EACH chave OF dados.key valor is variant = dados[chave] valorStr is string IF valor = Null THEN valorStr = "" ELSE IF TypeOf(valor) = typString THEN valorStr = """" + Replace(valor, """", """""") + """" ELSE valorStr = valor END csvResult += chave + "," + valorStr + CR END END Result csvResult END ``` //############################## O **WNetShare** é um sistema P2P (peer-to-peer) completo e inovador implementado com WLanguage, que permite compartilhamento de recursos distribuídos entre dispositivos na rede. Ele apresenta as seguintes funcionalidades incríveis: 1. **Descoberta Automática de Nós**: Utiliza UDP broadcast para descobrir automaticamente outros nós WNetShare na rede local. 2. **Compartilhamento de Recursos Heterogêneos**: Não se limita a arquivos - permite compartilhar: - Arquivos (com transferência em blocos e verificação de integridade) - Capacidade de processamento (executando funções remotamente) - Espaço de armazenamento - Streaming de mídia em tempo real 3. **Chat P2P Integrado**: Sistema de mensagens diretas entre peers sem servidor central. 4. **Streaming de Áudio P2P**: Transmissão de áudio em tempo real entre dois nós. 5. **Sistema de Busca Distribuída**: Os nós propagam consultas de busca pela rede, permitindo localizar recursos em qualquer peer conectado. 6. **Comunicação Robusta**: - Protocolo baseado em JSON para mensagens de controle - Transferência eficiente de dados binários - Verificação de integridade via hashes SHA-256 - Reconexão automática de peers conhecidos 7. **Sistema de Processamento Distribuído**: Permite delegar tarefas a outros nós, como criptografia, compressão ou conversões de dados. //############################## ``` // ========== FUNCIONALIDADES AVANÇADAS ========== // Sistema de sincronização de diretório P2P Class DiretorioSincronizadoP2P netShare is WNetShareManager // Gerenciador da rede P2P diretorioLocal is string // Caminho local do diretório diretorioVirtual is string // Nome do diretório virtual peersSincronizando is array of string // Lista de peers sincronizando iniciadoEm is datetime // Momento de início da sincronização ultimaSincronizacao is datetime // Última sincronização completa arquivosIgnorados is array of strings // Padrões de arquivos a ignorar // Cria um diretório sincronizado PROCEDURE IniciarSincronizacao(caminho is string, nomeVirtual is string = "") // Verifica se o diretório existe IF fDirExist(caminho) = False THEN Trace("Erro: Diretório não encontrado: " + caminho) Result False END diretorioLocal = caminho // Se não informou nome virtual, usa o nome da pasta IF nomeVirtual = "" THEN diretorioVirtual = fExtractPath(caminho, fDirectory) ELSE diretorioVirtual = nomeVirtual END // Adiciona padrões de ignorados padrão ArrayAdd(arquivosIgnorados, "*.tmp") ArrayAdd(arquivosIgnorados, "*.bak") ArrayAdd(arquivosIgnorados, "*.~*") ArrayAdd(arquivosIgnorados, "Thumbs.db") // Inicializa timestamps iniciadoEm = Now() ultimaSincronizacao = Now() // Cria um recurso para o diretório sincronizado recursoDir is Recurso recursoDir.nome = "Diretório: " + diretorioVirtual recursoDir.tipo = 10 // Tipo personalizado para diretório recursoDir.proprietarioId = netShare.idLocal // Metadados do diretório metaDir is JSON metaDir.nome = diretorioVirtual metaDir.descricao = "Diretório sincronizado P2P" metaDir.caminhoLocal = diretorioLocal metaDir.numArquivos = ContarArquivosDir(diretorioLocal) metaDir.tamanhoTotal = TamanhoTotalDir(diretorioLocal) recursoDir.metadados = JSONToString(metaDir) // Adiciona aos recursos locais ArrayAdd(netShare.recursosLocais, recursoDir) // Inicia thread de monitoramento de mudanças ThreadExecute(MonitorarMudancas, threadNormal) Trace("Diretório sincronizado iniciado: " + diretorioVirtual) Result True END // Thread que monitora mudanças no diretório THREAD PROCEDURE MonitorarMudancas() // Gera lista inicial de arquivos listaArquivos is array of DirFileInfo listaArquivos = GerarListaArquivos(diretorioLocal) // Loop principal de monitoramento WHILE True // Aguarda um tempo antes de verificar novamente Delay(5000) // 5 segundos // Gera nova lista novaLista is array of DirFileInfo novaLista = GerarListaArquivos(diretorioLocal) // Compara com a lista anterior mudancas is DirectoryChanges = CompararListasArquivos(listaArquivos, novaLista) // Se houve mudanças, notifica peers IF mudancas.adicionados.Count > 0 OR mudancas.modificados.Count > 0 OR mudancas.removidos.Count > 0 THEN NotificarMudancas(mudancas) ultimaSincronizacao = Now() END // Atualiza lista para próxima comparação listaArquivos = novaLista END END // Gera lista de arquivos no diretório PROCEDURE GerarListaArquivos(diretorio is string) resultado is array of DirFileInfo // Busca recursivamente BuscarArquivosRecursivo(diretorio, resultado, "") Result resultado END // Busca arquivos recursivamente em um diretório PROCEDURE BuscarArquivosRecursivo(diretorio is string, lista is array of DirFileInfo, prefixoRelativo is string) // Lista arquivos no diretório atual arquivos is array of strings = fListFile(diretorio + "\*.*", frNotDirectory) // Processa cada arquivo FOR EACH arquivo OF arquivos // Verifica se deve ignorar ignorar is boolean = False FOR EACH padrao OF arquivosIgnorados IF fWildcard(arquivo, padrao) THEN ignorar = True Break END END IF ignorar = False THEN // Adiciona à lista caminhoCompleto is string = diretorio + "\" + arquivo info is DirFileInfo info.nome = arquivo info.caminhoRelativo = prefixoRelativo + arquivo info.tamanho = fSizeFile(caminhoCompleto) info.dataModificacao = fDateFile(caminhoCompleto) info.hash = CalcularHashArquivo(caminhoCompleto) ArrayAdd(lista, info) END END // Lista subdiretórios diretorios is array of strings = fListDir(diretorio + "\*.*", frDirectory + frNotRecursive) // Processa cada subdiretório FOR EACH subdir OF diretorios // Ignora . e .. IF subdir <> "." AND subdir <> ".." THEN novoPrefixo is string = prefixoRelativo + subdir + "\" BuscarArquivosRecursivo(diretorio + "\" + subdir, lista, novoPrefixo) END END END // Calcula hash de um arquivo PROCEDURE CalcularHashArquivo(caminhoArquivo is string) // Para arquivos pequenos, calcula hash completo IF fSizeFile(caminhoArquivo) < 1024 * 1024 * 10 THEN // Menos de 10MB conteudo is Buffer = fLoadBuffer(caminhoArquivo) Result HashString(HASH_SHA256, conteudo) ELSE // Para arquivos grandes, calcula hash parcial (início, meio e fim) buffer is Buffer hashCalculado is string // Abre arquivo arquivoId is int = fOpen(caminhoArquivo, foRead) IF arquivoId = -1 THEN Result "" END // Lê primeiro bloco (10KB) blocoInicio is Buffer = fReadBufferBlock(arquivoId, 10240) // Posiciona no meio fSeek(arquivoId, fSizeFile(caminhoArquivo) / 2, soFromBeginning) blocoMeio is Buffer = fReadBufferBlock(arquivoId, 10240) // Posiciona próximo ao final fSeek(arquivoId, Max(0, fSizeFile(caminhoArquivo) - 10240), soFromBeginning) blocoFim is Buffer = fReadBufferBlock(arquivoId, 10240) // Fecha arquivo fClose(arquivoId) // Concatena blocos para calcular hash buffer = blocoInicio + blocoMeio + blocoFim hashCalculado = HashString(HASH_SHA256, buffer) Result hashCalculado END END // Compara duas listas de arquivos e retorna as mudanças PROCEDURE CompararListasArquivos(listaAntiga is array of DirFileInfo, listaNova is array of DirFileInfo) mudancas is DirectoryChanges // Verifica arquivos adicionados e modificados FOR EACH arquivoNovo OF listaNova arquivoEncontrado is boolean = False FOR EACH arquivoAntigo OF listaAntiga IF arquivoNovo.caminhoRelativo = arquivoAntigo.caminhoRelativo THEN arquivoEncontrado = True // Verifica se foi modificado IF arquivoNovo.hash <> arquivoAntigo.hash OR arquivoNovo.tamanho <> arquivoAntigo.tamanho OR arquivoNovo.dataModificacao <> arquivoAntigo.dataModificacao THEN ArrayAdd(mudancas.modificados, arquivoNovo) END Break END END // Se não encontrou, foi adicionado IF arquivoEncontrado = False THEN ArrayAdd(mudancas.adicionados, arquivoNovo) END END // Verifica arquivos removidos FOR EACH arquivoAntigo OF listaAntiga arquivoEncontrado is boolean = False FOR EACH arquivoNovo OF listaNova IF arquivoNovo.caminhoRelativo = arquivoAntigo.caminhoRelativo THEN arquivoEncontrado = True Break END END // Se não encontrou, foi removido IF arquivoEncontrado = False THEN ArrayAdd(mudancas.removidos, arquivoAntigo) END END Result mudancas END // Notifica peers sobre mudanças no diretório PROCEDURE NotificarMudancas(mudancas is DirectoryChanges) msg is JSON msg.tipo = "DIR_MUDANCAS" msg.diretorio = diretorioVirtual msg.adicionados = mudancas.adicionados msg.modificados = mudancas.modificados msg.removidos = mudancas.removidos msg.timestamp = Now() jsonMsg is string = JSONToString(msg) // Envia para peers que estão sincronizando FOR EACH peerId OF peersSincronizando FOR i = 1 TO ArrayCount(netShare.peers) IF netShare.peers[i].id = peerId AND netShare.peers[i].status = Peer.PEER_STATUS_CONECTADO THEN netShare.peers[i].socket.Send(jsonMsg) Break END END END Trace("Notificadas " + (ArrayCount(mudancas.adicionados) + ArrayCount(mudancas.modificados) + ArrayCount(mudancas.removidos)) + " mudanças no diretório " + diretorioVirtual) END // Solicita sincronização com um peer PROCEDURE SolicitarSincronizacao(peerId is string) // Procura o peer peerEncontrado is boolean = False peerSocket is Socket FOR i = 1 TO ArrayCount(netShare.peers) IF netShare.peers[i].id = peerId AND netShare.peers[i].status = Peer.PEER_STATUS_CONECTADO THEN peerEncontrado = True peerSocket = netShare.peers[i].socket Break END END // Se não encontrou ou não está conectado, retorna erro IF peerEncontrado = False OR peerSocket = Null THEN Trace("Erro: Peer não encontrado ou desconectado") Result False END // Envia solicitação msg is JSON msg.tipo = "DIR_SOLICITAR_SYNC" msg.diretorio = diretorioVirtual peerSocket.Send(JSONToString(msg)) // Adiciona à lista de peers sincronizando IF peerId NOT IN peersSincronizando THEN ArrayAdd(peersSincronizando, peerId) END Trace("Solicitada sincronização com " + peerId + " para diretório " + diretorioVirtual) Result True END // Calcula total de arquivos no diretório PROCEDURE ContarArquivosDir(diretorio is string) total is int = 0 // Conta arquivos no diretório atual arquivos is array of strings = fListFile(diretorio + "\*.*", frNotDirectory) total += ArrayCount(arquivos) // Lista subdiretórios diretorios is array of strings = fListDir(diretorio + "\*.*", frDirectory + frNotRecursive) // Processa cada subdiretório FOR EACH subdir OF diretorios // Ignora . e .. IF subdir <> "." AND subdir <> ".." THEN total += ContarArquivosDir(diretorio + "\" + subdir) END END Result total END // Calcula tamanho total do diretório PROCEDURE TamanhoTotalDir(diretorio is string) total is int8 = 0 // Soma tamanho dos arquivos no diretório atual arquivos is array of strings = fListFile(diretorio + "\*.*", frNotDirectory) FOR EACH arquivo OF arquivos total += fSizeFile(diretorio + "\" + arquivo) END // Lista subdiretórios diretorios is array of strings = fListDir(diretorio + "\*.*", frDirectory + frNotRecursive) // Processa cada subdiretório FOR EACH subdir OF diretorios // Ignora . e .. IF subdir <> "." AND subdir <> ".." THEN total += TamanhoTotalDir(diretorio + "\" + subdir) END END Result total END END // Estrutura para informações de arquivo em diretório Class DirFileInfo nome is string // Nome do arquivo caminhoRelativo is string // Caminho relativo à raiz do diretório compartilhado tamanho is int8 // Tamanho em bytes dataModificacao is datetime // Data de última modificação hash is string // Hash SHA-256 do conteúdo (ou parcial para arquivos grandes) END // Estrutura para armazenar mudanças em diretório Class DirectoryChanges adicionados is array of DirFileInfo // Arquivos novos modificados is array of DirFileInfo // Arquivos alterados removidos is array of DirFileInfo // Arquivos removidos END ``` //############################## O sistema **WNetShare** é uma implementação inovadora de rede peer-to-peer (P2P) em WLanguage que vai muito além de uma simples troca de arquivos. Vamos explorar as principais características que o tornam único: ### Características Inovadoras 1. **Versatilidade de Recursos Compartilháveis** - Compartilhamento de qualquer tipo de recurso: arquivos, capacidade de processamento, armazenamento, streaming - Sistema de metadados flexível baseado em JSON para descrever recursos - Verificação de integridade com hash SHA-256 2. **Descoberta Inteligente de Nós** - Descoberta automática via UDP broadcast - Propagação de conhecimento sobre peers (um nó apresenta outros nós) - Reconexão automática a peers conhecidos 3. **Comunicação Robusta** - Protocolo baseado em JSON para mensagens de controle - Transferência otimizada de dados binários em blocos - Flow control para prevenir sobrecarga da rede - Detecção de desconexão e reconexão transparente 4. **Sistema de Diretório Sincronizado** - Sincronização bidirecional de diretórios entre peers - Detecção eficiente de mudanças (adição, modificação, remoção) - Hash otimizado para arquivos grandes (usando amostragem) - Filtros para ignorar arquivos temporários 5. **Recursos Avançados** - Chat P2P integrado para comunicação direta - Streaming de áudio em tempo real - Sistema de processamento distribuído para delegação de tarefas ### Como Usar A implementação do WNetShare é simples de usar: ``` // Iniciar o sistema manager is WNetShareManager("Meu Computador") manager.Iniciar() // Compartilhar um arquivo manager.CompartilharArquivo("C:\dados\documento.pdf", "Relatório Anual", "Relatório financeiro anual da empresa") // Iniciar um diretório sincronizado dirSync is DiretorioSincronizadoP2P dirSync.netShare = manager dirSync.IniciarSincronizacao("C:\projetos\documentos", "Documentos do Projeto") // Buscar recursos na rede recursos is array of Recurso = manager.BuscarRecursos("relatório") // Enviar mensagem para um peer chat is ChatP2P chat.Iniciar(manager) chat.EnviarMensagem("ID-do-peer", "Olá, já viu o novo relatório?") ``` ### Vantagens sobre Implementações em Outras Linguagens Comparado com implementações similares em Python ou Java, o WNetShare em WLanguage oferece: 1. **Código mais conciso**: As funções nativas de rede, criptografia e manipulação de JSON do WLanguage reduzem drasticamente a quantidade de código necessário. 2. **Performance superior**: Implementação com menos camadas intermediárias, resultando em maior velocidade. 3. **Integração perfeita**: Fácil integração com interfaces WinDev/WebDev/Mobile e acesso ao sistema de arquivos. 4. **Segurança integrada**: Funções nativas de criptografia e hash facilitam a implementação de verificação de integridade. 5. **Multi-plataforma natural**: Funciona em Windows, Linux, iOS e Android graças à portabilidade do WLanguage. Este sistema P2P pode ser aplicado em diversos cenários, como: - Colaboração em equipes distribuídas - Compartilhamento de recursos em redes locais - Backup distribuído e redundante - Aplicações de comunicação segura - Processamento distribuído para tarefas intensivas A implementação aproveita ao máximo os recursos nativos do WLanguage para criar uma solução robusta e elegante que seria muito mais complexa de desenvolver em outras linguagens. Bons estudos Desafio está lançado consegue fazer funcionar? -- Adriano José Boller ______________________________________________ Consultor e Representante Oficial da PcSoft no Brasil +55 (41) 99949 1800 adrianoboller@gmail.com skype: adrianobollerhttp://wxinformatica.com.br/
Membre enregistré 3 851 messages
Posté le 01 avril 2025 - 16:41
Continuando com mais funcionalidades avançadas e casos de uso do sistema WNetShare: //############################## ``` // ========== RECURSOS BLOCKCHAIN DISTRIBUÍDO ========== // Sistema de validação distribuída usando blockchain simplificada Class BlockchainP2P netShare is WNetShareManager // Gerenciador da rede P2P chain is array of DataBlock // A cadeia de blocos transacoesPendentes is array of Transaction // Transações pendentes dificuldade is int = 2 // Dificuldade de mineração (zeros iniciais) // Inicializa a blockchain PROCEDURE Iniciar() // Cria o bloco gênesis se a cadeia estiver vazia IF ArrayCount(chain) = 0 THEN CriarBlocoGenesis() END // Inicia thread de mineração ThreadExecute(ThreadMineracao, threadNormal) Trace("BlockchainP2P iniciada") Result True END // Cria o bloco gênesis (primeiro bloco) PROCEDURE CriarBlocoGenesis() genesis is DataBlock genesis.index = 0 genesis.timestamp = Now() genesis.previousHash = "0" genesis.nonce = 0 genesis.data = "Bloco Genesis WNetShare" // Calcula o hash do bloco gênesis genesis.hash = CalcularHash(genesis) // Adiciona à cadeia ArrayAdd(chain, genesis) Trace("Bloco gênesis criado. Hash: " + genesis.hash) END // Calcula o hash de um bloco PROCEDURE CalcularHash(bloco is DataBlock) dados is string = [ StrToString(bloco.index) + DateTimeToString(bloco.timestamp, "yyyyMMddhhmmss") + bloco.previousHash + bloco.data + StrToString(bloco.nonce) ] Result HashString(HASH_SHA256, dados) END // Adiciona uma nova transação PROCEDURE AdicionarTransacao(transacao is Transaction) // Verifica se a transação é válida IF VerificarTransacao(transacao) = False THEN Trace("Transação inválida") Result False END // Adiciona às transações pendentes ArrayAdd(transacoesPendentes, transacao) // Propaga para outros peers EnviarTransacaoPeers(transacao) Trace("Transação adicionada e propagada: " + transacao.id) Result True END // Verifica a validade de uma transação PROCEDURE VerificarTransacao(transacao is Transaction) // Verificação básica para exemplo // Em um sistema real, incluiria verificação de assinaturas digitais IF transacao.id = "" OR transacao.origem = "" OR transacao.dados = "" THEN Result False END Result True END // Thread de mineração de novos blocos THREAD PROCEDURE ThreadMineracao() WHILE True // Verifica se há transações pendentes suficientes IF ArrayCount(transacoesPendentes) < 1 THEN // Aguarda até ter transações Delay(5000) NEXT END // Minera um novo bloco MinerarBloco() // Pequena pausa antes de tentar novamente Delay(1000) END END // Minera um novo bloco PROCEDURE MinerarBloco() ultimoBloco is DataBlock = chain[ArrayCount(chain)] // Prepara o novo bloco novoBloco is DataBlock novoBloco.index = ultimoBloco.index + 1 novoBloco.timestamp = Now() novoBloco.previousHash = ultimoBloco.hash // Combina todas as transações pendentes em uma string dadosTransacoes is string = "" FOR EACH transacao OF transacoesPendentes dadosTransacoes += transacao.id + transacao.origem + transacao.timestamp + transacao.dados END novoBloco.data = dadosTransacoes novoBloco.nonce = 0 // Realiza prova de trabalho (mining) prefixoAlvo is string = RepeatString("0", dificuldade) Trace("Iniciando mineração do bloco " + novoBloco.index) WHILE Left(novoBloco.hash, dificuldade) <> prefixoAlvo novoBloco.nonce++ novoBloco.hash = CalcularHash(novoBloco) // A cada 5000 tentativas, mostra progresso IF novoBloco.nonce % 5000 = 0 THEN Trace("Minerando... tentativa " + novoBloco.nonce) END END // Bloco minerado com sucesso Trace("Bloco minerado! Nonce: " + novoBloco.nonce + ", Hash: " + novoBloco.hash) // Adiciona à cadeia ArrayAdd(chain, novoBloco) // Limpa transações pendentes transacoesPendentes = new array of Transaction // Propaga o bloco para os peers EnviarBlocoPeers(novoBloco) END // Envia uma transação para os peers PROCEDURE EnviarTransacaoPeers(transacao is Transaction) msg is JSON msg.tipo = "BC_TRANSACAO" msg.transacao = transacao jsonMsg is string = JSONToString(msg) // Envia para todos os peers conectados FOR i = 1 TO ArrayCount(netShare.peers) IF netShare.peers[i].status = Peer.PEER_STATUS_CONECTADO THEN netShare.peers[i].socket.Send(jsonMsg) END END END // Envia um bloco para os peers PROCEDURE EnviarBlocoPeers(bloco is DataBlock) msg is JSON msg.tipo = "BC_BLOCO" msg.bloco = bloco jsonMsg is string = JSONToString(msg) // Envia para todos os peers conectados FOR i = 1 TO ArrayCount(netShare.peers) IF netShare.peers[i].status = Peer.PEER_STATUS_CONECTADO THEN netShare.peers[i].socket.Send(jsonMsg) END END END // Recebe um bloco de um peer PROCEDURE ReceberBloco(bloco is DataBlock) // Verifica se o bloco é válido IF VerificarBloco(bloco) = False THEN Trace("Bloco recebido inválido") Result False END // Verifica se o índice é o próximo da cadeia ultimoBloco is DataBlock = chain[ArrayCount(chain)] IF bloco.index <> ultimoBloco.index + 1 THEN Trace("Bloco recebido com índice inválido") Result False END // Adiciona à cadeia ArrayAdd(chain, bloco) // Limpa transações que já estão no bloco LimparTransacoesConfirmadas(bloco) Trace("Bloco recebido e adicionado à cadeia: " + bloco.index) Result True END // Verifica se um bloco é válido PROCEDURE VerificarBloco(bloco is DataBlock) // Verifica o hash do bloco hashCalculado is string = CalcularHash(bloco) IF bloco.hash <> hashCalculado THEN Trace("Hash inválido") Result False END // Verifica se o hash atende à dificuldade prefixoAlvo is string = RepeatString("0", dificuldade) IF Left(bloco.hash, dificuldade) <> prefixoAlvo THEN Trace("Hash não atende à dificuldade") Result False END Result True END // Limpa transações que já foram confirmadas em um bloco PROCEDURE LimparTransacoesConfirmadas(bloco is DataBlock) // Este é um exemplo simplificado // Em um sistema real, precisaria comparar as transações individualmente // Para este exemplo, apenas limpamos todas as transações pendentes transacoesPendentes = new array of Transaction END // Verifica a integridade da blockchain PROCEDURE VerificarBlockchain() // Percorre a cadeia verificando cada bloco FOR i = 1 TO ArrayCount(chain) blocoAtual is DataBlock = chain[i] // Verifica o hash do bloco hashCalculado is string = CalcularHash(blocoAtual) IF blocoAtual.hash <> hashCalculado THEN Trace("Bloco " + blocoAtual.index + " tem hash inválido") Result False END // Se não é o primeiro bloco, verifica ligação com anterior IF i > 1 THEN blocoAnterior is DataBlock = chain[i-1] IF blocoAtual.previousHash <> blocoAnterior.hash THEN Trace("Bloco " + blocoAtual.index + " não está ligado corretamente ao anterior") Result False END END END Trace("Blockchain íntegra: " + ArrayCount(chain) + " blocos verificados") Result True END END // Estrutura para um bloco na blockchain Class DataBlock index is int // Posição na cadeia timestamp is datetime // Momento de criação data is string // Dados armazenados no bloco previousHash is string // Hash do bloco anterior hash is string // Hash deste bloco nonce is int // Número utilizado na prova de trabalho END // Estrutura para uma transação na blockchain Class Transaction id is string = GetUUID() // ID único da transação origem is string // ID do peer que originou a transação timestamp is datetime // Momento da criação dados is string // Dados da transação assinatura is string // Assinatura digital (opcional) END ``` //############################## //############################## ``` // ========== SISTEMA DE COLABORAÇÃO EM TEMPO REAL ========== // Implementação de editor de texto colaborativo P2P Class EditorColaborativoP2P netShare is WNetShareManager // Gerenciador da rede P2P documento is CollaborativeDocument // Documento em edição participantes is array of Peer // Peers participando da edição versaoAtual is int = 0 // Versão atual do documento operacoesPendentes is array of DocumentOperation // Operações pendentes intervaloSincronizacao is int = 2000 // Intervalo de sincronização (ms) // Inicia o editor colaborativo PROCEDURE Iniciar(nomeDocumento is string, conteudoInicial is string = "") // Cria o documento documento = new CollaborativeDocument documento.nome = nomeDocumento documento.conteudo = conteudoInicial documento.criadoEm = Now() documento.ultimaModificacao = Now() documento.autorId = netShare.idLocal documento.versao = 1 // Inicia thread de sincronização ThreadExecute(ThreadSincronizacao, threadNormal) Trace("Editor colaborativo iniciado: " + nomeDocumento) Result True END // Convida um peer para edição colaborativa PROCEDURE ConvidarPeer(peerId is string) // Procura o peer peerEncontrado is boolean = False peerSocket is Socket FOR i = 1 TO ArrayCount(netShare.peers) IF netShare.peers[i].id = peerId AND netShare.peers[i].status = Peer.PEER_STATUS_CONECTADO THEN peerEncontrado = True peerSocket = netShare.peers[i].socket ArrayAdd(participantes, netShare.peers[i]) Break END END // Se não encontrou ou não está conectado, retorna erro IF peerEncontrado = False OR peerSocket = Null THEN Trace("Erro: Peer não encontrado ou desconectado") Result False END // Envia convite msg is JSON msg.tipo = "EDITOR_CONVITE" msg.documento = documento peerSocket.Send(JSONToString(msg)) Trace("Convite enviado para " + peerId) Result True END // Aplica uma operação no documento PROCEDURE AplicarOperacao(operacao is DocumentOperation) // Verifica se a operação é válida IF operacao.tipo = DocumentOperation.TIPO_INSERCAO THEN // Operação de inserção IF operacao.posicao <= Length(documento.conteudo) THEN // Insere o texto na posição indicada documento.conteudo = Left(documento.conteudo, operacao.posicao) + operacao.texto + Mid(documento.conteudo, operacao.posicao + 1) ELSE Trace("Posição de inserção inválida") Result False END ELSE IF operacao.tipo = DocumentOperation.TIPO_REMOCAO THEN // Operação de remoção IF operacao.posicao <= Length(documento.conteudo) - operacao.tamanho THEN // Remove o texto da posição indicada documento.conteudo = Left(documento.conteudo, operacao.posicao) + Mid(documento.conteudo, operacao.posicao + operacao.tamanho + 1) ELSE Trace("Posição ou tamanho de remoção inválidos") Result False END ELSE Trace("Tipo de operação desconhecido") Result False END // Atualiza metadados do documento documento.ultimaModificacao = Now() documento.versao++ versaoAtual = documento.versao Trace("Operação aplicada, nova versão: " + documento.versao) Result True END // Realiza uma inserção no documento PROCEDURE Inserir(posicao is int, texto is string) // Cria a operação operacao is DocumentOperation operacao.tipo = DocumentOperation.TIPO_INSERCAO operacao.autorId = netShare.idLocal operacao.timestamp = Now() operacao.posicao = posicao operacao.texto = texto operacao.versaoBase = documento.versao // Aplica localmente AplicarOperacao(operacao) // Adiciona à lista de operações pendentes ArrayAdd(operacoesPendentes, operacao) Result True END // Realiza uma remoção no documento PROCEDURE Remover(posicao is int, tamanho is int) // Cria a operação operacao is DocumentOperation operacao.tipo = DocumentOperation.TIPO_REMOCAO operacao.autorId = netShare.idLocal operacao.timestamp = Now() operacao.posicao = posicao operacao.tamanho = tamanho operacao.versaoBase = documento.versao // Aplica localmente AplicarOperacao(operacao) // Adiciona à lista de operações pendentes ArrayAdd(operacoesPendentes, operacao) Result True END // Thread de sincronização com os participantes THREAD PROCEDURE ThreadSincronizacao() WHILE True // Verifica se há operações pendentes para sincronizar IF ArrayCount(operacoesPendentes) > 0 THEN SincronizarOperacoes() END // Aguarda antes da próxima sincronização Delay(intervaloSincronizacao) END END // Sincroniza operações pendentes com os participantes PROCEDURE SincronizarOperacoes() // Prepara mensagem com operações pendentes msg is JSON msg.tipo = "EDITOR_OPERACOES" msg.operacoes = operacoesPendentes msg.versaoAtual = documento.versao jsonMsg is string = JSONToString(msg) // Envia para todos os participantes FOR EACH peer OF participantes // Verifica se o peer ainda está conectado peerConectado is boolean = False FOR i = 1 TO ArrayCount(netShare.peers) IF netShare.peers[i].id = peer.id AND netShare.peers[i].status = Peer.PEER_STATUS_CONECTADO THEN netShare.peers[i].socket.Send(jsonMsg) peerConectado = True Break END END // Se não está mais conectado, remove da lista IF peerConectado = False THEN // Remove peer da lista de participantes FOR i = 1 TO ArrayCount(participantes) IF participantes[i].id = peer.id THEN ArrayDelete(participantes, i) Break END END END END // Limpa operações pendentes operacoesPendentes = new array of DocumentOperation END // Processa operações recebidas de outros participantes PROCEDURE ProcessarOperacoes(operacoes is array of DocumentOperation, versaoRemota is int) // Verifica a versão do documento IF versaoRemota < documento.versao THEN // O peer está desatualizado // Em uma implementação real, seria necessário um mecanismo de resolução de conflitos Trace("Recebidas operações de versão desatualizada") END // Aplica as operações recebidas FOR EACH operacao OF operacoes AplicarOperacao(operacao) END Trace("Processadas " + ArrayCount(operacoes) + " operações") END // Salva o documento atual PROCEDURE SalvarDocumento(caminhoArquivo is string) // Salva o conteúdo do documento fSaveText(caminhoArquivo, documento.conteudo) // Salva metadados em arquivo separado metadados is JSON metadados.nome = documento.nome metadados.versao = documento.versao metadados.criadoEm = documento.criadoEm metadados.ultimaModificacao = documento.ultimaModificacao metadados.autorId = documento.autorId fSaveText(caminhoArquivo + ".meta", JSONToString(metadados)) Trace("Documento salvo: " + caminhoArquivo) Result True END END // Estrutura de documento colaborativo Class CollaborativeDocument nome is string // Nome do documento conteudo is string // Conteúdo textual versao is int // Versão atual criadoEm is datetime // Data/hora de criação ultimaModificacao is datetime // Última modificação autorId is string // ID do autor original END // Estrutura para operações de edição Class DocumentOperation tipo is int // Tipo de operação (inserção, remoção) autorId is string // ID do autor da operação timestamp is datetime // Momento da operação posicao is int // Posição no texto texto is string // Texto a inserir (para inserção) tamanho is int // Tamanho a remover (para remoção) versaoBase is int // Versão do documento base para esta operação // Constantes para tipos de operação CONSTANT TIPO_INSERCAO = 1 CONSTANT TIPO_REMOCAO = 2 END ``` //############################## //############################## ``` // ========== EXEMPLO DE APLICAÇÃO COMPLETA ========== // Aplicação completa do WNetShare com interface Procedure AplicacaoWNetShareCompleta() // Inicializa o sistema principal manager is WNetShareManager("WNetShare " + Now()) manager.Iniciar() // Inicializa os módulos adicionais chat is ChatP2P chat.Iniciar(manager) blockchain is BlockchainP2P blockchain.netShare = manager blockchain.Iniciar() editor is EditorColaborativoP2P editor.netShare = manager editor.Iniciar("Documento Colaborativo", "Bem-vindo ao editor colaborativo WNetShare!") dirSync is DiretorioSincronizadoP2P dirSync.netShare = manager // Compartilha recursos de exemplo CompartilharRecursosExemplo(manager) // Conecta a peers conhecidos ConectarPeersConhecidos(manager) // Exibe informações do sistema ExibirInformacoesWNetShare(manager) // Abriria interface gráfica em um sistema real // Aqui apenas simulamos algumas operações SimularOperacoesWNetShare(manager, blockchain, editor, dirSync, chat) // Em uma aplicação real, o sistema ficaria rodando // até o usuário decidir encerrá-lo // Finaliza os módulos manager.Finalizar() END // Compartilha recursos de exemplo Procedure CompartilharRecursosExemplo(manager is WNetShareManager) // Cria uma pasta de exemplos se não existir diretorioExemplos is string = fCurrentDir() + "\exemplos" IF fDirExist(diretorioExemplos) = False THEN fMakeDir(diretorioExemplos) END // Cria alguns arquivos de exemplo arquivoTexto is string = diretorioExemplos + "\documento.txt" fSaveText(arquivoTexto, "Este é um documento de exemplo para o sistema WNetShare.") // Compartilha o arquivo manager.CompartilharArquivo(arquivoTexto, "Documento de Texto", "Exemplo de compartilhamento de arquivo") // Compartilha funções de processamento recursoProc is Recurso recursoProc.nome = "Funções de Processamento" recursoProc.tipo = Recurso.TIPO_PROCESSAMENTO metaProc is JSON metaProc.funcoes = ["CALCULAR_HASH", "CRIPTOGRAFAR", "COMPRIMIR"] metaProc.descricao = "Funções de processamento disponíveis para a rede" recursoProc.metadados = JSONToString(metaProc) recursoProc.proprietarioId = manager.idLocal ArrayAdd(manager.recursosLocais, recursoProc) Trace("Recursos de exemplo compartilhados") END // Conecta a peers conhecidos a partir de um arquivo Procedure ConectarPeersConhecidos(manager is WNetShareManager) // Verifica se existe arquivo com peers conhecidos arquivoPeers is string = fCurrentDir() + "\peers.cfg" IF fFileExist(arquivoPeers) = True THEN conteudo is string = fLoadText(arquivoPeers) linhas is array of strings = Split(conteudo, CR) // Tenta conectar a cada peer FOR EACH linha OF linhas // Ignora linhas vazias e comentários IF linha <> "" AND Left(linha, 1) <> "#" THEN manager.ConectarAoPeer(linha) END END END END // Exibe informações do sistema Procedure ExibirInformacoesWNetShare(manager is WNetShareManager) info is string = [ === WNetShare P2P v1.0 === ID do Nó: ~manager.idLocal~ Nome: ~manager.nomeLocal~ Porta: ~manager.portaEscuta~ Recursos locais compartilhados: ~ArrayCount(manager.recursosLocais)~ Peers conectados: ~ContagemPeersConectados(manager)~ Sistema P2P iniciado com sucesso! ] Info(info) END // Conta peers conectados Procedure ContagemPeersConectados(manager is WNetShareManager) contador is int = 0 FOR EACH peer OF manager.peers IF peer.status = Peer.PEER_STATUS_CONECTADO THEN contador++ END END Result contador END // Simula algumas operações para demonstração Procedure SimularOperacoesWNetShare(manager is WNetShareManager, blockchain is BlockchainP2P, editor is EditorColaborativoP2P, dirSync is DiretorioSincronizadoP2P, chat is ChatP2P) // Simula edição no editor colaborativo editor.Inserir(Length(editor.documento.conteudo), " Adicionando um novo parágrafo.") editor.Inserir(Length(editor.documento.conteudo), CR + CR + "Este documento está sendo editado colaborativamente.") // Simulamos uma remoção editor.Remover(10, 5) // Simula uma transação blockchain transacao is Transaction transacao.origem = manager.idLocal transacao.timestamp = Now() transacao.dados = "Teste de transação WNetShare: " + DateTimeToString(Now()) blockchain.AdicionarTransacao(transacao) // Simula compartilhamento de diretório dirTeste is string = fCurrentDir() + "\teste_sync" IF fDirExist(dirTeste) = False THEN fMakeDir(dirTeste) fSaveText(dirTeste + "\arquivo1.txt", "Conteúdo do arquivo 1") fSaveText(dirTeste + "\arquivo2.txt", "Conteúdo do arquivo 2") END dirSync.IniciarSincronizacao(dirTeste, "Pasta de Teste") // Simula envio de mensagem de chat (se houvesse outro peer conectado) IF ArrayCount(manager.peers) > 0 THEN FOR EACH peer OF manager.peers IF peer.status = Peer.PEER_STATUS_CONECTADO THEN chat.EnviarMensagem(peer.id, "Olá! Esta é uma mensagem de teste do WNetShare.") Break END END END // Exibe o status atual Info([ === Simulação WNetShare === Editor colaborativo: - Versão atual: ~editor.documento.versao~ - Tamanho do documento: ~Length(editor.documento.conteudo)~ caracteres Blockchain: - Blocos: ~ArrayCount(blockchain.chain)~ - Transações pendentes: ~ArrayCount(blockchain.transacoesPendentes)~ Diretório sincronizado: - Caminho: ~dirSync.diretorioLocal~ - Nome virtual: ~dirSync.diretorioVirtual~ Simulação concluída! ]) END ``` //############################## Agora, vamos explorar os casos de uso mais avançados e as vantagens competitivas do WNetShare: ### Casos de Uso Avançados 1. **Colaboração em Escritórios Distribuídos** O WNetShare permite que equipes geograficamente distribuídas trabalhem em documentos e projetos de forma colaborativa e em tempo real. A sincronização de diretórios e o editor colaborativo P2P eliminam a necessidade de servidores centrais e reduzem a latência de sincronização. 2. **Sistemas de Backup Distribuído** Empresas podem implementar soluções de backup redundante peer-to-peer, onde arquivos importantes são replicados entre vários nós, garantindo alta disponibilidade e resistência a falhas. 3. **Validação Descentralizada de Documentos** O componente blockchain permite a validação e certificação descentralizada de documentos importantes, como contratos, criando um registro imutável de quando e por quem um documento foi criado ou modificado. 4. **Compartilhamento de Recursos Computacionais** Organizações podem distribuir cargas de trabalho computacionalmente intensivas entre vários dispositivos, utilizando ciclos de processamento ociosos para tarefas como renderização, análise de dados ou processos em lote. 5. **Aplicações IoT Distribuídas** Dispositivos IoT podem formar uma rede mesh utilizando o WNetShare para comunicação direta e processamento distribuído, reduzindo a dependência de infraestrutura centralizada na nuvem. 6. **Sistemas de Comunicação Resilientes** Em áreas com conectividade instável ou em situações de emergência, o WNetShare permite criar redes de comunicação resilientes que continuam funcionando mesmo quando partes da infraestrutura falham. ### Vantagens Competitivas do WNetShare em WLanguage 1. **Desenvolvimento Rápido** - O código em WLanguage é significativamente mais conciso que equivalentes em outras linguagens - Funções nativas para sockets, threads, criptografia e JSON reduzem o código necessário - Implementações similares em Java ou Python exigiriam 2-3x mais linhas de código 2. **Performance Otimizada** - Acesso direto a recursos de rede e sistema sem camadas intermediárias - Gerenciamento eficiente de memória - Operações de criptografia e hash otimizadas nativamente 3. **Segurança Integrada** - Funções criptográficas robustas integradas na linguagem - Verificação de integridade com hash SHA-256 nativo - Assinaturas digitais simplificadas 4. **Escalabilidade** - O sistema suporta facilmente de dezenas a centenas de nós - Gerenciamento eficiente de recursos em redes grandes - Descoberta inteligente 5. **Integração Perfeita** - Integração natural com interfaces WinDev, WebDev e WinDev Mobile - Compatibilidade com Bases de Dados HFSQL e outras - Interação direta com sistemas de arquivos e recursos do sistema operacional 6. **Multi-plataforma Nativo** - Execução em Windows, Linux, iOS e Android sem modificações - Mesma base de código funciona em desktops, servidores e dispositivos móveis - Adaptação automática a diferentes ambientes de rede 7. **Manutenção Simplificada** - Código mais conciso resulta em menos bugs e maior legibilidade - Estrutura orientada a objetos facilita extensões e modificações - Separação clara entre componentes do sistema //############################## ``` // ========== EXTENSÕES AVANÇADAS ========== // Sistema de reputação e confiança para peers Class SistemaReputacaoP2P netShare is WNetShareManager // Gerenciador da rede P2P reputacoes is associative array of Reputacao // Mapa de IDs para reputações historicoPontuacoes is array of ReputacaoEvento // Histórico de eventos // Inicializa o sistema de reputação PROCEDURE Iniciar() // Carrega reputações anteriores, se existirem CarregarReputacoes() Trace("Sistema de reputação P2P iniciado") Result True END // Atualiza a reputação de um peer PROCEDURE AtualizarReputacao(peerId is string, pontos is real, motivo is string) // Se é a primeira interação com este peer, inicializa IF peerId NOT IN reputacoes.key THEN reputacoes[peerId] = new Reputacao reputacoes[peerId].id = peerId reputacoes[peerId].pontuacao = 50.0 // Valor inicial neutro reputacoes[peerId].ultimaAtualizacao = Now() reputacoes[peerId].transacoes = 0 END // Registra o evento evento is ReputacaoEvento evento.peerId = peerId evento.pontos = pontos evento.motivo = motivo evento.timestamp = Now() ArrayAdd(historicoPontuacoes, evento) // Atualiza a pontuação novaReputacao is real = reputacoes[peerId].pontuacao + pontos // Limita entre 0 e 100 reputacoes[peerId].pontuacao = Min(100, Max(0, novaReputacao)) reputacoes[peerId].ultimaAtualizacao = Now() reputacoes[peerId].transacoes++ Trace("Reputação de " + peerId + " atualizada: " + reputacoes[peerId].pontuacao) Result reputacoes[peerId].pontuacao END // Avalia se um peer é confiável PROCEDURE EhConfiavel(peerId is string) IF peerId NOT IN reputacoes.key THEN // Peer desconhecido, assume neutro Result True // Para peers desconhecidos, damos o benefício da dúvida END // Verifica a pontuação Result (reputacoes[peerId].pontuacao >= 40.0) END // Avalia se um peer é altamente confiável PROCEDURE EhAltamenteConfiavel(peerId is string) IF peerId NOT IN reputacoes.key THEN // Peer desconhecido não é altamente confiável Result False END // Verifica a pontuação Result (reputacoes[peerId].pontuacao >= 75.0) END // Obtém a reputação de um peer PROCEDURE ObterReputacao(peerId is string) IF peerId NOT IN reputacoes.key THEN // Peer desconhecido, retorna valor padrão rep is Reputacao rep.id = peerId rep.pontuacao = 50.0 rep.ultimaAtualizacao = Now() rep.transacoes = 0 Result rep END Result reputacoes[peerId] END // Salva as reputações atuais PROCEDURE SalvarReputacoes() // Prepara estrutura para salvar dados is JSON dados.reputacoes = reputacoes // Salva em arquivo fSaveText(fCurrentDir() + "\reputacoes.json", JSONToString(dados)) Trace("Reputações salvas") END // Carrega reputações anteriores PROCEDURE CarregarReputacoes() arquivoReputacoes is string = fCurrentDir() + "\reputacoes.json" IF fFileExist(arquivoReputacoes) = True THEN TRY conteudo is string = fLoadText(arquivoReputacoes) dados is JSON = JSONParse(conteudo) reputacoes = dados.reputacoes Trace("Reputações carregadas: " + reputacoes.Count + " peers") CATCH Trace("Erro ao carregar reputações: " + ErrorInfo()) END END END // Avalia a reputação de um recurso baseado em seu proprietário PROCEDURE AvaliarRecurso(recurso is Recurso) // Retorna pontuação de confiabilidade para um recurso IF recurso.proprietarioId NOT IN reputacoes.key THEN // Proprietário desconhecido Result 50.0 // Neutro END Result reputacoes[recurso.proprietarioId].pontuacao END // Avalia eventos de rede e atualiza reputações automaticamente PROCEDURE AvaliarEventoRede(tipoEvento is int, peerId is string, dadosAdicionais is string) SWITCH tipoEvento CASE ReputacaoEvento.EVENTO_TRANSFERENCIA_SUCESSO: // Transferência bem-sucedida AtualizarReputacao(peerId, 2.0, "Transferência bem-sucedida: " + dadosAdicionais) CASE ReputacaoEvento.EVENTO_RECURSO_VALIDO: // Recurso fornecido era válido AtualizarReputacao(peerId, 1.0, "Recurso válido: " + dadosAdicionais) CASE ReputacaoEvento.EVENTO_TRANSFERENCIA_FALHA: // Falha na transferência AtualizarReputacao(peerId, -3.0, "Falha na transferência: " + dadosAdicionais) CASE ReputacaoEvento.EVENTO_RECURSO_INVALIDO: // Recurso inválido ou corrompido AtualizarReputacao(peerId, -5.0, "Recurso inválido: " + dadosAdicionais) CASE ReputacaoEvento.EVENTO_COMPORTAMENTO_SUSPEITO: // Comportamento suspeito detectado AtualizarReputacao(peerId, -10.0, "Comportamento suspeito: " + dadosAdicionais) END END END // Estrutura para armazenar reputação de um peer Class Reputacao id is string // ID do peer pontuacao is real // Pontuação (0-100) ultimaAtualizacao is datetime // Última atualização transacoes is int // Número de transações END // Estrutura para eventos de reputação Class ReputacaoEvento peerId is string // ID do peer pontos is real // Pontos atribuídos (+/-) motivo is string // Motivo da atualização timestamp is datetime // Momento do evento // Constantes para tipos de eventos CONSTANT EVENTO_TRANSFERENCIA_SUCESSO = 1 CONSTANT EVENTO_RECURSO_VALIDO = 2 CONSTANT EVENTO_TRANSFERENCIA_FALHA = 3 CONSTANT EVENTO_RECURSO_INVALIDO = 4 CONSTANT EVENTO_COMPORTAMENTO_SUSPEITO = 5 END // Sistema de Analytics P2P Class AnalyticsP2P netShare is WNetShareManager // Gerenciador da rede P2P eventos is array of AnalyticEvento // Registro de eventos metricas is Metricas // Métricas atuais intervaloExportacao is int = 3600 // Intervalo para exportar dados (segundos) ultimaExportacao is datetime // Última exportação // Inicializa o sistema de analytics PROCEDURE Iniciar() // Inicializa métricas metricas = new Metricas metricas.inicioRegistro = Now() // Inicia thread de monitoramento periódico ThreadExecute(ThreadMonitoramento, threadNormal) // Inicia exportação periódica ThreadExecute(ThreadExportacao, threadNormal) Trace("Sistema de Analytics P2P iniciado") Result True END // Registra um evento PROCEDURE RegistrarEvento(tipo is int, descricao is string, metadados is string = "") evento is AnalyticEvento evento.tipo = tipo evento.timestamp = Now() evento.descricao = descricao evento.metadados = metadados // Adiciona ao histórico ArrayAdd(eventos, evento) // Atualiza métricas conforme o tipo de evento AtualizarMetricas(evento) END // Atualiza as métricas com base em um evento PROCEDURE AtualizarMetricas(evento is AnalyticEvento) // Incrementa contador geral de eventos metricas.totalEventos++ // Atualiza métricas específicas por tipo SWITCH evento.tipo CASE AnalyticEvento.TIPO_CONEXAO: // Evento de conexão metricas.conexoes++ CASE AnalyticEvento.TIPO_DESCONEXAO: // Evento de desconexão metricas.desconexoes++ CASE AnalyticEvento.TIPO_TRANSFERENCIA: // Evento de transferência de dados metricas.transferencias++ // Extrai tamanho da transferência dos metadados, se disponível TRY metaJSON is JSON = JSONParse(evento.metadados) IF metaJSON.tamanho <> Null THEN metricas.bytesTransferidos += metaJSON.tamanho END CATCH // Ignora se não conseguir extrair END CASE AnalyticEvento.TIPO_BUSCA: // Evento de busca metricas.buscas++ CASE AnalyticEvento.TIPO_RECURSO_CRIADO: // Evento de criação de recurso metricas.recursosCompartilhados++ CASE AnalyticEvento.TIPO_ERRO: // Evento de erro metricas.erros++ END END // Thread de monitoramento periódico THREAD PROCEDURE ThreadMonitoramento() WHILE True // Coleta métricas atuais da rede ColetarMetricasRede() // Pequena pausa Delay(30000) // 30 segundos END END // Thread para exportação periódica de dados THREAD PROCEDURE ThreadExportacao() WHILE True // Verifica se é hora de exportar IF DateDifference(ultimaExportacao, Now(), dtSecond) > intervaloExportacao THEN ExportarDados() ultimaExportacao = Now() END // Aguarda um tempo antes de verificar novamente Delay(60000) // 1 minuto END END // Coleta métricas atuais da rede PROCEDURE ColetarMetricasRede() // Atualiza métricas de rede metricas.peersAtivos = 0 metricas.recursosDisponiveis = ArrayCount(netShare.recursosRede) FOR EACH peer OF netShare.peers IF peer.status = Peer.PEER_STATUS_CONECTADO THEN metricas.peersAtivos++ END END // Métricas de tempo ativo metricas.tempoAtivo = DateDifference(metricas.inicioRegistro, Now(), dtSecond) END // Exporta os dados coletados PROCEDURE ExportarDados() // Prepara estrutura para exportação dados is JSON dados.timestamp = Now() dados.metricas = metricas dados.eventos = ArrayExtract(eventos, Max(1, ArrayCount(eventos) - 100), 100) // Últimos 100 eventos // Salva em arquivo de log com timestamp nomeArquivo is string = "analytics_" + DateToString(Today(), "yyyyMMdd") + ".json" // Verifica se pasta de logs existe diretorioLogs is string = fCurrentDir() + "\logs" IF fDirExist(diretorioLogs) = False THEN fMakeDir(diretorioLogs) END // Salva o arquivo fSaveText(diretorioLogs + "\" + nomeArquivo, JSONToString(dados)) Trace("Dados de analytics exportados para: " + nomeArquivo) END // Gera um relatório resumido PROCEDURE GerarRelatorio() // Atualiza métricas antes de gerar o relatório ColetarMetricasRede() // Métricas derivadas taxaErro is real = 0 IF metricas.totalEventos > 0 THEN taxaErro = (metricas.erros * 100) / metricas.totalEventos END tempoAtivoHoras is real = metricas.tempoAtivo / 3600.0 // Constrói o relatório relatorio is string = [ === Relatório de Analytics WNetShare === Período: ~DateTimeToString(metricas.inicioRegistro)~ até ~DateTimeToString(Now())~ Tempo ativo: ~tempoAtivoHoras~ horas MÉTRICAS GERAIS: - Total de eventos: ~metricas.totalEventos~ - Peers ativos: ~metricas.peersAtivos~ - Recursos disponíveis: ~metricas.recursosDisponiveis~ ATIVIDADE DE REDE: - Conexões: ~metricas.conexoes~ - Desconexões: ~metricas.desconexoes~ - Transferências: ~metricas.transferencias~ - Dados transferidos: ~FormatarBytes(metricas.bytesTransferidos)~ - Buscas realizadas: ~metricas.buscas~ SAÚDE DO SISTEMA: - Taxa de erros: ~taxaErro~% - Recursos compartilhados: ~metricas.recursosCompartilhados~ EVENTOS RECENTES: ~FormatarEventosRecentes()~ === Fim do Relatório === ] Result relatorio END // Formata os eventos recentes para o relatório PROCEDURE FormatarEventosRecentes() limite is int = 10 // Exibe até 10 eventos recentes resultado is string = "" FOR i = Max(1, ArrayCount(eventos) - limite) TO ArrayCount(eventos) evento is AnalyticEvento = eventos[i] resultado += DateTimeToString(evento.timestamp, "dd/MM/yyyy HH:mm:ss") + ": " + evento.descricao + CR END Result resultado END // Formata bytes para exibição legível PROCEDURE FormatarBytes(bytes is int8) IF bytes < 1024 THEN Result bytes + " B" ELSE IF bytes < 1024 * 1024 THEN Result Round(bytes / 1024, 2) + " KB" ELSE IF bytes < 1024 * 1024 * 1024 THEN Result Round(bytes / (1024 * 1024), 2) + " MB" ELSE Result Round(bytes / (1024 * 1024 * 1024), 2) + " GB" END END END // Estrutura para evento de analytics Class AnalyticEvento tipo is int // Tipo de evento timestamp is datetime // Momento do evento descricao is string // Descrição curta metadados is string // Metadados adicionais em JSON // Constantes para tipos de eventos CONSTANT TIPO_CONEXAO = 1 CONSTANT TIPO_DESCONEXAO = 2 CONSTANT TIPO_TRANSFERENCIA = 3 CONSTANT TIPO_BUSCA = 4 CONSTANT TIPO_RECURSO_CRIADO = 5 CONSTANT TIPO_ERRO = 6 END // Estrutura para métricas do sistema Class Metricas // Métricas gerais totalEventos is int = 0 // Total de eventos registrados inicioRegistro is datetime // Momento de início do registro tempoAtivo is int = 0 // Tempo ativo em segundos // Métricas de rede peersAtivos is int = 0 // Peers atualmente conectados conexoes is int = 0 // Total de conexões desconexoes is int = 0 // Total de desconexões transferencias is int = 0 // Total de transferências bytesTransferidos is int8 = 0 // Bytes transferidos buscas is int = 0 // Buscas realizadas // Métricas de recursos recursosDisponiveis is int = 0 // Recursos disponíveis na rede recursosCompartilhados is int = 0 // Recursos compartilhados por este nó // Métricas de saúde erros is int = 0 // Contagem de erros END ``` //############################## ### Aplicações Práticas do WNetShare O WNetShare não é apenas um exercício teórico - ele tem aplicações práticas significativas em diversos setores: 1. **Ambientes de Trabalho Distribuídos** - **Desafio**: Equipes remotas precisam colaborar em tempo real em documentos e código. - **Solução WNetShare**: O Editor Colaborativo P2P e a Sincronização de Diretórios permitem edição simultânea e sincronização sem depender de servidores centrais. - **Benefício**: Redução de latência, possibilidade de trabalho offline com sincronização posterior, e controle total sobre os dados. 2. **Sistemas de Saúde** - **Desafio**: Documentação médica precisa ser compartilhada entre profissionais mantendo privacidade e disponibilidade. - **Solução WNetShare**: Blockchain P2P para validação imutável e compartilhamento direto entre instituições autorizadas. - **Benefício**: Eliminação da necessidade de intermediários, garantia de autenticidade dos registros, e distribuição controlada. 3. **Operações de Campo** - **Desafio**: Equipes trabalhando em áreas remotas com conectividade limitada precisam compartilhar dados. - **Solução WNetShare**: Modo mesh com sincronização oportunista e priorização de dados críticos. - **Benefício**: Continuidade operacional mesmo em condições adversas de rede, com sincronização quando possível. 4. **Inteligência Distribuída em IoT** - **Desafio**: Dispositivos IoT produzem grandes volumes de dados que são caros para transmitir à nuvem. - **Solução WNetShare**: Processamento Colaborativo que permite que dispositivos analisem dados localmente e compartilhem apenas resultados. - **Benefício**: Redução de custos de transmissão, menor latência e maior privacidade. 5. **Sistemas de Backup Resilientes** - **Desafio**: Dados críticos precisam ser protegidos contra falhas e desastres. - **Solução WNetShare**: Replicação P2P com Sistema de Reputação garantindo confiabilidade dos nós de armazenamento. - **Benefício**: Alta disponibilidade sem ponto único de falha e custo reduzido em relação a soluções de nuvem. ### Arquitetura Modular e Extensível O design modular do WNetShare torna-o especialmente poderoso e adaptável: 1. **Módulos Independentes**: Cada componente (gerenciamento P2P, blockchain, editor colaborativo, etc.) pode ser usado independentemente ou em conjunto. 2. **Extensibilidade**: Novos tipos de recursos e funcionalidades podem ser adicionados sem modificar o núcleo do sistema. 3. **Composabilidade**: As aplicações podem escolher os componentes necessários para suas necessidades específicas. 4. **Níveis de Abstração**: Os desenvolvedores podem trabalhar em diferentes níveis - desde a API de alto nível até os detalhes de rede de baixo nível. ### Considerações para Implantação em Produção Para utilizar o WNetShare em um ambiente real de produção, algumas considerações adicionais seriam necessárias: 1. **Segurança Avançada**: - Implementação de criptografia ponta-a-ponta para todas as comunicações - Validação rigorosa de identidade de peers - Proteção contra ataques DDoS e Sybil 2. **Escalabilidade**: - Otimização da descoberta de peers para redes muito grandes - Estruturas de roteamento hierárquicas para reduzir tráfego de broadcast - Mecanismos adaptativos para equilibrar carga entre peers 3. **Gerenciamento de Recursos**: - Limitação inteligente de banda e CPU - Priorização de tráfego crítico - Monitoramento avançado de desempenho 4. **Resolução de Conflitos**: - Algoritmos sofisticados para resolver conflitos em edições colaborativas - Estratégias para lidar com partições temporárias na rede 5. **Interfaces de Usuário**: - Desenvolvimento de interfaces WYSIWYG completas para cada funcionalidade - Dashboards de monitoramento em tempo real - Assistentes para configuração e diagnóstico ### Conclusão O WNetShare demonstra o poder e a elegância do WLanguage para criar sistemas distribuídos complexos e robustos. Esta implementação combina: - Comunicação peer-to-peer avançada - Recursos distribuídos heterogêneos - Edição colaborativa em tempo real - Validação descentralizada via blockchain - Sincronização de diretórios - Sistema de reputação e confiança - Analytics P2P Tudo isso implementado de forma concisa, legível e eficiente, aproveitando ao máximo os recursos nativos do WLanguage para criar uma solução que seria muito mais complexa de desenvolver em outras linguagens de programação. O sistema pode ser usado como base para uma ampla variedade de aplicações distribuídas, desde colaboração em escritórios até sistemas IoT avançados, demonstrando a versatilidade e o poder da plataforma WX. Bons estudos -- Adriano José Boller ______________________________________________ Consultor e Representante Oficial da PcSoft no Brasil +55 (41) 99949 1800 adrianoboller@gmail.com skype: adrianobollerhttp://wxinformatica.com.br/
Membre enregistré 3 851 messages
Posté le 01 avril 2025 - 17:20
Bom dia! Mesmo sendo um projeto robusto, existem várias oportunidades para melhorar e expandir o WNetShare. Vamos analisar os pontos de melhoria possíveis: ### 1. Segurança Avançada - **Criptografia de Ponta-a-Ponta**: Implementar um sistema completo E2EE (End-to-End Encryption) usando algoritmos modernos como ChaCha20-Poly1305 ou AES-GCM. - **Assinaturas de Mensagens**: Assinar todas as mensagens de rede para evitar ataques man-in-the-middle. - **Prova de Trabalho Anti-Spam**: Mecanismo para evitar flood de mensagens na rede. - **Autenticação Multifator**: Para acesso inicial à rede, especialmente em ambientes corporativos. - **Zero-Knowledge Proofs**: Para validação de identidade sem revelar informações sensíveis. ### 2. Escalabilidade e Performance - **Protocolo DHT (Distributed Hash Table)**: Implementar Kademlia ou Chord para descoberta de peers mais eficiente em redes grandes. - **Fragmentação de Dados**: Dividir arquivos grandes em fragmentos distribuídos para melhor resiliência e performance. - **Streaming Adaptativo**: Ajustar qualidade de streams de mídia baseado na capacidade da rede. - **Cache Inteligente**: Armazenar dados frequentemente acessados localmente com estratégias de invalidação. - **Compressão Adaptativa**: Selecionar algoritmos de compressão baseados no tipo de conteúdo e necessidades de performance. ### 3. Resistência e Confiabilidade - **Mecanismo Anti-Eclipse**: Proteger contra ataques onde um nó é isolado do resto da rede. - **Redundância Inteligente**: Replicar dados críticos baseado em análise de risco e padrões de uso. - **Detecção de Malware**: Verificar arquivos compartilhados contra assinaturas de malware. - **Verificação de Consistência**: Garantir que dados replicados mantêm-se consistentes entre nós. - **Rollback e Versionamento**: Sistema mais sofisticado para gerenciar conflitos e permitir retorno a versões anteriores. ### 4. Usabilidade e Integração - **API RESTful Completa**: Permitir que sistemas externos interajam facilmente com a rede WNetShare. - **Webhooks**: Notificações para sistemas externos quando eventos importantes ocorrem. - **Interface Administrativa Web**: Dashboard completo para gerenciamento e monitoramento. - **Integração com Serviços Existentes**: Conectores para Dropbox, Google Drive, etc. para migração simplificada. - **Sistema de Plugins**: Arquitetura para extensões de terceiros. ### 5. Recursos Inovadores - **Contratos Inteligentes P2P**: Sistema de regras executáveis para automatizar transações na rede. - **Machine Learning Distribuído**: Permitir treinamento distribuído de modelos entre peers. - **Sistema de Micropagamentos**: Implementar compensação para uso de recursos de outros peers. - **Redes Neurais Federadas**: Aprendizado colaborativo sem compartilhar dados brutos. - **Anonimização**: Camadas de roteamento tipo Tor para aumentar privacidade quando necessário. ### 6. Especificações Técnicas para WLanguage - **Otimização Multithreading**: Tirar maior proveito de CPUs multicore com paralelismo mais inteligente. - **Redução de Memória**: Otimizar estruturas de dados para menor footprint. - **APIs Nativas**: Usar APIs específicas dos sistemas operacionais para melhor performance. - **JIT para Scripts**: Implementar compilação Just-In-Time para scripts de processamento distribuído. - **Arquitetura Multi-Agente**: Sistemas de agentes autônomos para tarefas distribuídas complexas. ### 7. Testes e Monitoramento - **Simulação de Rede Adversarial**: Testar em condições de rede hostis e instáveis. - **Fuzzing de Protocolos**: Testes automatizados com entradas inesperadas para encontrar vulnerabilidades. - **Monitoramento Distribuído**: Sistema de telemetria e alertas distribuído pela rede. - **Balancers de Carga Auto-Ajustáveis**: Redistribuição dinâmica de carga entre peers. - **Benchmarks Automatizados**: Testes regulares de performance comparando com versões anteriores. ### 8. Documentação e Comunidade - **API de Referência Completa**: Documentação exaustiva para desenvolvedores. - **Exemplos de Casos de Uso**: Templates prontos para cenários comuns. - **Fórum da Comunidade**: Espaço para discussão de melhorias e resolução de problemas. - **Programa de Contribuidores**: Sistema para incentivar contribuições externas. - **Certificação de Conformidade**: Validação formal para integrações críticas. ### 9. Recursos Específicos do WLanguage - **Integração com Ferramentas PCSoft**: Conectores para WINDEV, WEBDEV e WINDEV Mobile. - **Componentes Visuais Especializados**: Controles para monitorar e gerenciar a rede P2P. - **Serialização Binária Otimizada**: Aproveitando os formatos nativos do WLanguage. - **Transformação de Queries HFSQL**: Distribuição de consultas entre nós da rede. - **Mapeamento para UML de Projeto**: Documentação automatizada usando ferramentas PCSoft. ### 10. Compatibilidade e Interoperabilidade - **Compatibilidade com Protocolos Padrão**: BitTorrent, IPFS, WebRTC para interoperabilidade. - **Implementações em Múltiplas Linguagens**: Clientes compatíveis em outras linguagens para ecossistema mais amplo. - **Compatibilidade com IoT**: Suporte para dispositivos com recursos limitados. - **Proxies e Bridges**: Para integração com redes fechadas ou legadas. - **Geração de SDKs**: Criação automática de bibliotecas cliente. ### Cronograma Sugerido de Implementação 1. **Curto Prazo (1-3 meses)**: - Melhorias de segurança prioritárias (criptografia E2EE, assinaturas) - Otimizações de performance em pontos críticos - Interface administrativa básica - Testes em condições adversas 2. **Médio Prazo (3-6 meses)**: - Implementação de DHT para escalabilidade - Sistema de plugins - API RESTful e documentação - Fragmentação de dados e redundância inteligente 3. **Longo Prazo (6-12 meses)**: - Recursos inovadores (contratos inteligentes, ML distribuído) - Integrações com serviços externos - Sistema de micropagamentos - Certificações de segurança ### Orçamento Estimado Para uma implementação completa dessas melhorias, seria necessário considerar um orçamento que abrange: - Desenvolvimento: 5-8 desenvolvedores WLanguage experientes - Teste e QA: 2-3 especialistas em teste de sistemas distribuídos - Infraestrutura: Ambiente de teste simulando redes de 1000+ nós - Segurança: Auditoria externa e pentests - Documentação e Suporte: 1-2 escritores técnicos Isso representaria um investimento significativo, possivelmente na faixa de R$ 1-2 milhões para uma implementação comercial completa, dependendo do escopo final e dos recursos priorizados. O WNetShare já é um projeto robusto e inovador, mas com essas melhorias, ele poderia se tornar uma plataforma verdadeiramente revolucionária para comunicação e colaboração descentralizada, com aplicações em diversos setores de mercado. -- Adriano José Boller ______________________________________________ Consultor e Representante Oficial da PcSoft no Brasil +55 (41) 99949 1800 adrianoboller@gmail.com skype: adrianobollerhttp://wxinformatica.com.br/
Membre enregistré 3 851 messages
Posté le 01 avril 2025 - 18:03
Verdão 2.0 Vou redesenhar o WNetShare com foco em uma implementação mais segura e específica do WLanguage, evitando exceções e verificando adequadamente a existência de arquivos. Vou dividir o sistema em classes menores e bem definidas, com funções específicas e tratamento de erros adequado. //############################## ``` // WNetShare: Sistema P2P Seguro e Resiliente // Versão 2.0 - Implementação com WLanguage // CLASSE: Config - Gerenciamento de configurações Class Config // Variáveis privadas para armazenar configurações PRIVATE configFile is string // Caminho do arquivo de configuração PRIVATE iniSection is string = "WNetShare" // Seção padrão do arquivo INI PRIVATE defaultPort is int = 13579 // Porta padrão PRIVATE defaultMaxPeers is int = 50 // Máximo de peers padrão // Construtor PROCEDURE CONSTRUCTOR(cfgPath is string = "") // Se não foi informado caminho, usa o padrão IF cfgPath = "" THEN configFile = fCurrentDir() + "\wnetshare.ini" ELSE configFile = cfgPath END // Verificar se o arquivo existe, se não, criar com configurações padrão IF NOT fFileExist(configFile) THEN CreateDefaultConfig() END END // Cria arquivo de configuração com valores padrão PROCEDURE CreateDefaultConfig() // Verificar se o diretório existe dirPath is string = fExtractPath(configFile, fDirectory) IF dirPath <> "" AND NOT fDirExist(dirPath) THEN IF NOT fMakeDir(dirPath) THEN Trace("Não foi possível criar o diretório de configuração: " + dirPath) RETURN END END // Escrever configurações padrão INIWrite("Version", "2.0", iniSection, configFile) INIWrite("Port", defaultPort, iniSection, configFile) INIWrite("MaxPeers", defaultMaxPeers, iniSection, configFile) INIWrite("NodeName", "WNetShare Node " + DateToString(Today(), "yyyyMMdd"), iniSection, configFile) INIWrite("ResourceDir", fCurrentDir() + "\resources", iniSection, configFile) INIWrite("DownloadDir", fCurrentDir() + "\downloads", iniSection, configFile) INIWrite("EnableDiscovery", "True", iniSection, configFile) INIWrite("DiscoveryPort", "13580", iniSection, configFile) INIWrite("LogLevel", "3", iniSection, configFile) INIWrite("ConnectionTimeout", "5000", iniSection, configFile) INIWrite("EnableCompression", "True", iniSection, configFile) INIWrite("EnableEncryption", "True", iniSection, configFile) Trace("Arquivo de configuração criado: " + configFile) END // Obter valor de configuração PROCEDURE GetValue(key is string, defaultValue is string) : string // Verificar se o arquivo existe IF NOT fFileExist(configFile) THEN Trace("Arquivo de configuração não encontrado: " + configFile) RETURN defaultValue END // Ler valor do arquivo INI value is string = INIRead(key, iniSection, configFile) // Se não encontrou, retorna valor padrão IF value = "" THEN RETURN defaultValue END RETURN value END // Obter valor inteiro PROCEDURE GetIntValue(key is string, defaultValue is int) : int // Obter valor como string valueStr is string = GetValue(key, StrToString(defaultValue)) // Converter para inteiro TRY value is int = StringToInt(valueStr) RETURN value CATCH Trace("Erro ao converter valor para inteiro: " + valueStr) RETURN defaultValue END END // Obter valor booleano PROCEDURE GetBoolValue(key is string, defaultValue is boolean) : boolean // Obter valor como string valueStr is string = Lower(GetValue(key, defaultValue ? "True" : "False")) // Converter para booleano IF valueStr = "true" OR valueStr = "1" OR valueStr = "yes" OR valueStr = "y" THEN RETURN True ELSE IF valueStr = "false" OR valueStr = "0" OR valueStr = "no" OR valueStr = "n" THEN RETURN False ELSE RETURN defaultValue END END // Definir valor de configuração PROCEDURE SetValue(key is string, value is string) : boolean // Verificar se o arquivo existe IF NOT fFileExist(configFile) THEN // Tenta criar arquivo com configurações padrão CreateDefaultConfig() END // Escrever valor no arquivo INI IF NOT INIWrite(key, value, iniSection, configFile) THEN Trace("Erro ao escrever configuração: " + key) RETURN False END RETURN True END // Obter porta de comunicação PROCEDURE GetPort() : int RETURN GetIntValue("Port", defaultPort) END // Obter máximo de peers PROCEDURE GetMaxPeers() : int RETURN GetIntValue("MaxPeers", defaultMaxPeers) END // Obter nome do nó PROCEDURE GetNodeName() : string RETURN GetValue("NodeName", "WNetShare Node") END // Obter diretório de recursos PROCEDURE GetResourceDir() : string dir is string = GetValue("ResourceDir", fCurrentDir() + "\resources") // Verificar se o diretório existe, se não, tentar criar IF NOT fDirExist(dir) THEN IF NOT fMakeDir(dir) THEN Trace("Não foi possível criar o diretório de recursos: " + dir) // Retorna o diretório atual como fallback RETURN fCurrentDir() END END RETURN dir END // Obter diretório de downloads PROCEDURE GetDownloadDir() : string dir is string = GetValue("DownloadDir", fCurrentDir() + "\downloads") // Verificar se o diretório existe, se não, tentar criar IF NOT fDirExist(dir) THEN IF NOT fMakeDir(dir) THEN Trace("Não foi possível criar o diretório de downloads: " + dir) // Retorna o diretório atual como fallback RETURN fCurrentDir() END END RETURN dir END // Verificar se descoberta está habilitada PROCEDURE IsDiscoveryEnabled() : boolean RETURN GetBoolValue("EnableDiscovery", True) END // Obter porta de descoberta PROCEDURE GetDiscoveryPort() : int RETURN GetIntValue("DiscoveryPort", 13580) END // Obter nível de log PROCEDURE GetLogLevel() : int RETURN GetIntValue("LogLevel", 3) END // Obter timeout de conexão PROCEDURE GetConnectionTimeout() : int RETURN GetIntValue("ConnectionTimeout", 5000) END // Verificar se compressão está habilitada PROCEDURE IsCompressionEnabled() : boolean RETURN GetBoolValue("EnableCompression", True) END // Verificar se criptografia está habilitada PROCEDURE IsEncryptionEnabled() : boolean RETURN GetBoolValue("EnableEncryption", True) END END ``` //############################## //############################## ``` // CLASSE: Logger - Sistema de Logs Class Logger // Variáveis privadas PRIVATE logFile is string // Caminho do arquivo de log PRIVATE logLevel is int = 3 // Nível de log (1-5) PRIVATE logToFile is boolean = True // Habilita log em arquivo PRIVATE logToConsole is boolean = True // Habilita log no console // Constantes para níveis de log CONSTANT LEVEL_ERROR = 1 // Apenas erros críticos CONSTANT LEVEL_WARNING = 2 // Erros e alertas CONSTANT LEVEL_INFO = 3 // Informações gerais CONSTANT LEVEL_DEBUG = 4 // Detalhes de debug CONSTANT LEVEL_TRACE = 5 // Trace completo // Construtor PROCEDURE CONSTRUCTOR(level is int = 3, logPath is string = "") logLevel = level // Define caminho do arquivo de log IF logPath = "" THEN logFile = fCurrentDir() + "\logs\wnetshare_" + DateToString(Today(), "yyyyMMdd") + ".log" ELSE logFile = logPath END // Verificar e criar diretório de logs se necessário dirPath is string = fExtractPath(logFile, fDirectory) IF dirPath <> "" AND NOT fDirExist(dirPath) THEN IF NOT fMakeDir(dirPath) THEN logToFile = False // Desabilita log em arquivo Trace("Não foi possível criar o diretório de logs: " + dirPath) END END // Log inicial Info("Logger iniciado com nível " + logLevel) END // Registra mensagem de log PROCEDURE Log(message is string, level is int = LEVEL_INFO) // Verifica se este nível de log está habilitado IF level > logLevel THEN RETURN // Formata mensagem com timestamp timestamp is string = DateTimeToString(Now(), "yyyy-MM-dd HH:mm:ss") levelText is string SWITCH level CASE LEVEL_ERROR: levelText = "ERROR" CASE LEVEL_WARNING: levelText = "WARNING" CASE LEVEL_INFO: levelText = "INFO" CASE LEVEL_DEBUG: levelText = "DEBUG" CASE LEVEL_TRACE: levelText = "TRACE" DEFAULT: levelText = "UNKNOWN" END formattedMessage is string = timestamp + " [" + levelText + "] " + message // Log no console IF logToConsole THEN Trace(formattedMessage) END // Log em arquivo IF logToFile THEN // Verifica se o diretório existe dirPath is string = fExtractPath(logFile, fDirectory) IF dirPath <> "" AND NOT fDirExist(dirPath) THEN IF NOT fMakeDir(dirPath) THEN Trace("Não foi possível criar o diretório de logs: " + dirPath) RETURN END END // Tenta adicionar ao arquivo de log TRY fSaveTextAdd(logFile, formattedMessage + CR) CATCH // Se falhar, desabilita log em arquivo logToFile = False Trace("Falha ao escrever no arquivo de log: " + logFile) END END END // Log de erro PROCEDURE Error(message is string) Log(message, LEVEL_ERROR) END // Log de alerta PROCEDURE Warning(message is string) Log(message, LEVEL_WARNING) END // Log de informação PROCEDURE Info(message is string) Log(message, LEVEL_INFO) END // Log de debug PROCEDURE Debug(message is string) Log(message, LEVEL_DEBUG) END // Log de trace PROCEDURE Trace(message is string) Log(message, LEVEL_TRACE) END // Define nível de log PROCEDURE SetLevel(level is int) logLevel = level Info("Nível de log alterado para " + level) END // Habilita/desabilita log em arquivo PROCEDURE SetFileLogging(enable is boolean) logToFile = enable Info("Log em arquivo " + (enable ? "habilitado" : "desabilitado")) END // Habilita/desabilita log no console PROCEDURE SetConsoleLogging(enable is boolean) logToConsole = enable Info("Log no console " + (enable ? "habilitado" : "desabilitado")) END // Rotaciona log (cria novo arquivo) PROCEDURE RotateLog() IF NOT logToFile THEN RETURN // Define novo arquivo de log logFile = fExtractPath(logFile, fDirectory) + "\wnetshare_" + DateTimeToString(Now(), "yyyyMMdd_HHmmss") + ".log" Info("Log rotacionado: " + logFile) END END ``` //############################## //############################## ``` // CLASSE: FileResource - Recurso de arquivo Class FileResource // Propriedades do recurso de arquivo id is string // ID único do recurso name is string // Nome amigável filePath is string // Caminho local do arquivo hash is string = "" // Hash SHA-256 do conteúdo size is int8 = 0 // Tamanho em bytes mimeType is string = "" // Tipo MIME createdAt is datetime // Data de criação ownerId is string // ID do proprietário ownerName is string // Nome do proprietário isAvailable is boolean = True // Disponibilidade // Construtor PROCEDURE CONSTRUCTOR(fileName is string, path is string, owner is string, oName is string) id = GetUUID() // Gera UUID único name = fileName filePath = path ownerId = owner ownerName = oName createdAt = Now() // Inicializa informações do arquivo, se existir IF fFileExist(path) THEN // Obtém tamanho size = fSizeFile(path) // Determina o tipo MIME mimeType = DetermineMimeType(path) ELSE isAvailable = False END END // Determina o tipo MIME com base na extensão PROCEDURE DetermineMimeType(path is string) : string extension is string = Lower(fExtractPath(path, fExtension)) SWITCH extension CASE ".txt": RETURN "text/plain" CASE ".html", ".htm": RETURN "text/html" CASE ".css": RETURN "text/css" CASE ".js": RETURN "application/javascript" CASE ".json": RETURN "application/json" CASE ".xml": RETURN "application/xml" CASE ".pdf": RETURN "application/pdf" CASE ".zip": RETURN "application/zip" CASE ".doc", ".docx": RETURN "application/msword" CASE ".xls", ".xlsx": RETURN "application/vnd.ms-excel" CASE ".ppt", ".pptx": RETURN "application/vnd.ms-powerpoint" CASE ".jpg", ".jpeg": RETURN "image/jpeg" CASE ".png": RETURN "image/png" CASE ".gif": RETURN "image/gif" CASE ".svg": RETURN "image/svg+xml" CASE ".mp3": RETURN "audio/mpeg" CASE ".wav": RETURN "audio/wav" CASE ".mp4": RETURN "video/mp4" CASE ".avi": RETURN "video/x-msvideo" CASE ".csv": RETURN "text/csv" DEFAULT: RETURN "application/octet-stream" END END // Calcula hash do arquivo PROCEDURE CalculateHash() : string // Se o arquivo não existe, retorna string vazia IF NOT fFileExist(filePath) THEN RETURN "" END // Para arquivos pequenos, calcula hash diretamente IF size < 10 * 1024 * 1024 THEN // Menos de 10MB buffer is Buffer = fLoadBuffer(filePath) hash = HashString(HASH_SHA256, buffer) ELSE // Para arquivos grandes, calculate em blocos hash = CalculateHashLargeFile() END RETURN hash END // Calcula hash para arquivos grandes em blocos PROCEDURE CalculateHashLargeFile() : string // Verifica se o arquivo existe IF NOT fFileExist(filePath) THEN RETURN "" END // Abre o arquivo fileHandle is int = fOpen(filePath, foRead + foShareRead) IF fileHandle = -1 THEN RETURN "" END // Inicializa contexto de hash hashContext is int = HashInit(HASH_SHA256) IF hashContext = 0 THEN fClose(fileHandle) RETURN "" END // Processa o arquivo em blocos de 1MB blockSize is int = 1024 * 1024 buffer is Buffer WHILE NOT fEOF(fileHandle) buffer = fReadBufferBlock(fileHandle, blockSize) IF buffer <> "" THEN HashAddBuffer(hashContext, buffer) END END // Obtém o hash final finalHash is string = HashEnd(hashContext) // Fecha o arquivo fClose(fileHandle) RETURN finalHash END // Verifica se o arquivo ainda existe e está acessível PROCEDURE CheckAvailability() : boolean // Verifica se o arquivo existe isAvailable = fFileExist(filePath) // Se existe, atualiza tamanho IF isAvailable THEN size = fSizeFile(filePath) END RETURN isAvailable END // Serializa para JSON PROCEDURE Serialize() : string jsonData is JSON jsonData.id = id jsonData.name = name jsonData.hash = hash jsonData.size = size jsonData.mimeType = mimeType jsonData.createdAt = createdAt jsonData.ownerId = ownerId jsonData.ownerName = ownerName jsonData.isAvailable = isAvailable // Não incluímos o filePath por segurança RETURN JSONToString(jsonData) END // Deserializa de JSON PROCEDURE Deserialize(jsonStr is string) : boolean // Verifica se a string não está vazia IF jsonStr = "" THEN RETURN False END TRY jsonData is JSON = JSONParse(jsonStr) // Copia os campos id = jsonData.id name = jsonData.name hash = jsonData.hash size = jsonData.size mimeType = jsonData.mimeType createdAt = jsonData.createdAt ownerId = jsonData.ownerId ownerName = jsonData.ownerName isAvailable = jsonData.isAvailable RETURN True CATCH RETURN False END END END ``` //############################## //############################## ``` // CLASSE: Peer - Representação de um peer na rede Class Peer // Informações básicas id is string // ID único do peer name is string // Nome amigável address is string // Endereço IP:porta publicKey is string // Chave pública (opcional) status is int = STATUS_UNKNOWN // Status atual lastSeen is datetime // Último contato socket is Socket // Socket de comunicação // Estatísticas failedAttempts is int = 0 // Contagem de falhas consecutivas successfulTransfers is int = 0 // Transferências bem-sucedidas resourceCount is int = 0 // Número de recursos // Constantes para status CONSTANT STATUS_UNKNOWN = 0 // Status desconhecido CONSTANT STATUS_CONNECTING = 1 // Conectando CONSTANT STATUS_CONNECTED = 2 // Conectado CONSTANT STATUS_DISCONNECTED = 3 // Desconectado CONSTANT STATUS_FAILED = 4 // Falha na conexão // Construtor PROCEDURE CONSTRUCTOR(peerId is string, peerName is string, peerAddress is string) id = peerId name = peerName address = peerAddress lastSeen = Now() END // Verifica se está conectado PROCEDURE IsConnected() : boolean RETURN (status = STATUS_CONNECTED AND socket <> Null AND socket..Valid AND socket..Estado = socketConectado) END // Atualiza o status PROCEDURE UpdateStatus(newStatus is int) // Atualiza o status status = newStatus // Se conectou, atualiza timestamp IF newStatus = STATUS_CONNECTED THEN lastSeen = Now() failedAttempts = 0 END // Se falhou, incrementa contador IF newStatus = STATUS_FAILED OR newStatus = STATUS_DISCONNECTED THEN failedAttempts++ END END // Serializa para JSON PROCEDURE Serialize() : string jsonData is JSON jsonData.id = id jsonData.name = name jsonData.address = address jsonData.status = status jsonData.lastSeen = lastSeen jsonData.failedAttempts = failedAttempts jsonData.successfulTransfers = successfulTransfers jsonData.resourceCount = resourceCount // Não incluímos o socket na serialização RETURN JSONToString(jsonData) END // Deserializa de JSON PROCEDURE Deserialize(jsonStr is string) : boolean // Verifica se a string não está vazia IF jsonStr = "" THEN RETURN False END TRY jsonData is JSON = JSONParse(jsonStr) // Copia os campos id = jsonData.id name = jsonData.name address = jsonData.address status = jsonData.status lastSeen = jsonData.lastSeen failedAttempts = jsonData.failedAttempts successfulTransfers = jsonData.successfulTransfers resourceCount = jsonData.resourceCount RETURN True CATCH RETURN False END END // Fecha a conexão PROCEDURE CloseConnection() IF socket <> Null AND socket..Valid THEN socket.Close() END status = STATUS_DISCONNECTED END END ``` //############################## //############################## ``` // CLASSE: P2PMessage - Mensagem para comunicação P2P Class P2PMessage // Informações da mensagem id is string // ID único da mensagem type is int // Tipo da mensagem (ver constantes) senderId is string // ID do remetente recipientId is string // ID do destinatário (vazio = broadcast) timestamp is datetime // Momento de criação payload is string // Conteúdo (JSON) // Constantes para tipos de mensagem CONSTANT TYPE_HELLO = 1 // Apresentação CONSTANT TYPE_GOODBYE = 2 // Despedida CONSTANT TYPE_RESOURCE_LIST = 3 // Lista de recursos CONSTANT TYPE_RESOURCE_REQUEST = 4 // Solicita recurso CONSTANT TYPE_DATA_TRANSFER = 5 // Transferência de dados CONSTANT TYPE_PING = 6 // Ping CONSTANT TYPE_PONG = 7 // Resposta ao ping CONSTANT TYPE_SEARCH = 8 // Busca de recursos CONSTANT TYPE_SEARCH_RESULT = 9 // Resultado de busca CONSTANT TYPE_ERROR = 10 // Erro // Construtor PROCEDURE CONSTRUCTOR(messageType is int, senderID is string) id = GetUUID() // Gera UUID único type = messageType senderId = senderID timestamp = Now() END // Define payload PROCEDURE SetPayload(data is string) payload = data END // Define payload a partir de objeto JSON PROCEDURE SetJSONPayload(data is JSON) payload = JSONToString(data) END // Obtém payload como objeto JSON PROCEDURE GetJSONPayload() : JSON IF payload = "" THEN RETURN Null END TRY payloadJSON is JSON = JSONParse(payload) RETURN payloadJSON CATCH RETURN Null END END // Serializa mensagem para envio PROCEDURE Serialize() : string jsonMsg is JSON jsonMsg.id = id jsonMsg.type = type jsonMsg.senderId = senderId jsonMsg.recipientId = recipientId jsonMsg.timestamp = timestamp jsonMsg.payload = payload RETURN JSONToString(jsonMsg) END // Deserializa a partir de string PROCEDURE Deserialize(jsonStr is string) : boolean IF jsonStr = "" THEN RETURN False END TRY jsonMsg is JSON = JSONParse(jsonStr) id = jsonMsg.id type = jsonMsg.type senderId = jsonMsg.senderId recipientId = jsonMsg.recipientId timestamp = jsonMsg.timestamp payload = jsonMsg.payload RETURN True CATCH RETURN False END END // Cria uma mensagem de resposta PROCEDURE CreateResponse(responseType is int) : P2PMessage response is P2PMessage response.type = responseType response.senderId = recipientId response.recipientId = senderId RETURN response END END ``` //############################## //############################## ``` // CLASSE: ResourceManager - Gerencia recursos locais e remotos Class ResourceManager // Recursos do sistema localResources is array of FileResource // Recursos locais remoteResources is array of FileResource // Recursos conhecidos de outros peers // Diretórios resourceDir is string // Diretório para recursos downloadDir is string // Diretório para downloads nodeId is string // ID deste nó nodeName is string // Nome deste nó // Referências config is Config // Configurações logger is Logger // Sistema de logs // Construtor PROCEDURE CONSTRUCTOR(cfg is Config, log is Logger, id is string, name is string) // Salva referências config = cfg logger = log nodeId = id nodeName = name // Configura diretórios resourceDir = config.GetResourceDir() downloadDir = config.GetDownloadDir() // Carrega recursos persistentes LoadResources() logger.Info("ResourceManager inicializado para nó: " + nodeName) END // Adiciona um recurso local PROCEDURE AddLocalResource(resource is FileResource) : boolean // Verifica se o recurso é válido IF resource.name = "" OR resource.filePath = "" THEN logger.Warning("Recurso inválido, campos obrigatórios vazios") RETURN False END // Verifica se o arquivo existe IF NOT fFileExist(resource.filePath) THEN logger.Warning("Arquivo não encontrado: " + resource.filePath) RETURN False END // Verifica se já existe recurso com mesmo ID FOR i = 1 TO ArrayCount(localResources) IF localResources[i].id = resource.id THEN logger.Warning("Recurso com ID já existente: " + resource.id) RETURN False END END // Verifica se o hash foi calculado IF resource.hash = "" THEN // Calcular hash resource.hash = resource.CalculateHash() IF resource.hash = "" THEN logger.Warning("Falha ao calcular hash do arquivo: " + resource.filePath) END END // Adiciona à lista ArrayAdd(localResources, resource) // Persiste alterações SaveResources() logger.Info("Recurso local adicionado: " + resource.name + " (" + resource.id + ")") RETURN True END // Adiciona um recurso remoto PROCEDURE AddRemoteResource(resource is FileResource) : boolean // Verifica se o recurso é válido IF resource.name = "" OR resource.ownerId = "" THEN logger.Warning("Recurso remoto inválido, campos obrigatórios vazios") RETURN False END // Verifica se já existe recurso com mesmo ID FOR i = 1 TO ArrayCount(remoteResources) IF remoteResources[i].id = resource.id THEN logger.Warning("Recurso remoto com ID já existente: " + resource.id) RETURN False END END // Adiciona à lista ArrayAdd(remoteResources, resource) logger.Info("Recurso remoto adicionado: " + resource.name + " de " + resource.ownerName) RETURN True END // Compartilha um arquivo da máquina local PROCEDURE ShareFile(filePath is string, name is string = "") : FileResource // Verifica se o arquivo existe IF NOT fFileExist(filePath) THEN logger.Warning("Arquivo não encontrado: " + filePath) RETURN Null END // Se nome não informado, usa o nome do arquivo IF name = "" THEN name = fExtractPath(filePath, fFileName + fExtension) END // Cria o recurso resource is FileResource(name, filePath, nodeId, nodeName) // Calcula o hash resource.hash = resource.CalculateHash() // Adiciona o recurso IF AddLocalResource(resource) THEN RETURN resource ELSE RETURN Null END END // Remove um recurso local PROCEDURE RemoveLocalResource(resourceId is string) : boolean // Procura o recurso na lista de recursos locais FOR i = 1 TO ArrayCount(localResources) IF localResources[i].id = resourceId THEN // Remove da lista ArrayDelete(localResources, i) // Persiste alterações SaveResources() logger.Info("Recurso local removido: " + resourceId) RETURN True END END logger.Warning("Recurso local não encontrado para remoção: " + resourceId) RETURN False END // Remove um recurso remoto PROCEDURE RemoveRemoteResource(resourceId is string) : boolean // Procura o recurso na lista de recursos remotos FOR i = 1 TO ArrayCount(remoteResources) IF remoteResources[i].id = resourceId THEN // Remove da lista ArrayDelete(remoteResources, i) logger.Info("Recurso remoto removido: " + resourceId) RETURN True END END logger.Debug("Recurso remoto não encontrado para remoção: " + resourceId) RETURN False END // Obtém um recurso pelo ID PROCEDURE GetResource(resourceId is string, localOnly is boolean = False) : FileResource // Procura nos recursos locais FOR EACH resource OF localResources IF resource.id = resourceId THEN RETURN resource END END // Se localOnly, não procura nos remotos IF localOnly THEN RETURN Null END // Procura nos recursos remotos FOR EACH resource OF remoteResources IF resource.id = resourceId THEN RETURN resource END END // Não encontrado RETURN Null END // Pesquisa recursos por nome PROCEDURE SearchResources(searchTerm is string, localOnly is boolean = False) : array of FileResource results is array of FileResource searchTermLower is string = Lower(searchTerm) // Função auxiliar para verificar correspondência FUNCTION CheckMatch(resource is FileResource) : boolean IF Contains(Lower(resource.name), searchTermLower) THEN RETURN True END RETURN False END // Procura nos recursos locais FOR EACH resource OF localResources IF CheckMatch(resource) THEN ArrayAdd(results, resource) END END // Se localOnly, não procura nos remotos IF localOnly THEN RETURN results END // Procura nos recursos remotos FOR EACH resource OF remoteResources IF CheckMatch(resource) THEN ArrayAdd(results, resource) END END RETURN results END // Verifica se uma string contém outra PRIVATE PROCEDURE Contains(text is string, searchTerm is string) : boolean RETURN (Position(text, searchTerm) > 0) END // Salva recursos locais em arquivo PROCEDURE SaveResources() : boolean TRY // Criamos um array com as strings serializadas dos recursos serializedResources is array of string FOR EACH resource OF localResources serialized is string = resource.Serialize() IF serialized <> "" THEN ArrayAdd(serializedResources, serialized) END END // Prepara dados para salvar data is JSON data.resources = serializedResources // Define caminho do arquivo filePath is string = resourceDir + "\resources.json" // Garante que o diretório existe IF NOT fDirExist(resourceDir) THEN IF NOT fMakeDir(resourceDir) THEN logger.Error("Falha ao criar diretório de recursos: " + resourceDir) RETURN False END END // Salva o arquivo IF fSaveText(filePath, JSONToString(data)) THEN logger.Debug("Recursos salvos: " + ArrayCount(serializedResources) + " recursos") RETURN True ELSE logger.Error("Falha ao salvar recursos em: " + filePath) RETURN False END CATCH logger.Error("Erro ao salvar recursos: " + ErrorInfo()) RETURN False END END // Carrega recursos locais de arquivo PROCEDURE LoadResources() : boolean // Define caminho do arquivo filePath is string = resourceDir + "\resources.json" // Verifica se o arquivo existe IF NOT fFileExist(filePath) THEN logger.Info("Arquivo de recursos não encontrado: " + filePath) RETURN True // Não é erro, apenas não há recursos ainda END TRY // Lê o arquivo content is string = fLoadText(filePath) IF content = "" THEN logger.Warning("Arquivo de recursos vazio") RETURN True END // Faz o parse do JSON data is JSON = JSONParse(content) // Limpa a lista atual localResources = new array of FileResource // Deserializa cada recurso FOR EACH serialized OF data.resources resource is FileResource("", "", "", "") IF resource.Deserialize(serialized) THEN // Verifica se ainda existe o arquivo IF resource.CheckAvailability() THEN ArrayAdd(localResources, resource) ELSE logger.Warning("Arquivo não disponível para o recurso: " + resource.name) END ELSE logger.Warning("Falha ao deserializar recurso") END END logger.Info("Recursos carregados: " + ArrayCount(localResources) + " recursos") RETURN True CATCH logger.Error("Erro ao carregar recursos: " + ErrorInfo()) RETURN False END END // Gera lista de recursos para compartilhar PROCEDURE GenerateResourceList() : string data is JSON resources is array of JSON FOR EACH resource OF localResources // Verifica se o recurso ainda está disponível IF resource.CheckAvailability() THEN res is JSON res.id = resource.id res.name = resource.name res.size = resource.size res.hash = resource.hash res.mimeType = resource.mimeType ArrayAdd(resources, res) END END data.resources = resources RETURN JSONToString(data) END // Atualiza lista de recursos remotos de um peer PROCEDURE UpdateRemoteResources(peerId is string, peerName is string, resourceList is string) : int IF resourceList = "" THEN RETURN 0 END // Remove recursos atuais deste peer RemoveResourcesFromPeer(peerId) // Faz parse da lista TRY data is JSON = JSONParse(resourceList) addedCount is int = 0 FOR EACH resData OF data.resources // Cria o recurso resource is FileResource(resData.name, "", peerId, peerName) resource.id = resData.id resource.size = resData.size resource.hash = resData.hash resource.mimeType = resData.mimeType // Adiciona à lista IF AddRemoteResource(resource) THEN addedCount++ END END logger.Info("Atualizada lista de recursos de " + peerName + ": " + addedCount + " recursos") RETURN addedCount CATCH logger.Error("Erro ao processar lista de recursos: " + ErrorInfo()) RETURN 0 END END // Remove recursos de um peer específico PROCEDURE RemoveResourcesFromPeer(peerId is string) : int count is int = 0 // Remove todos os recursos deste peer FOR i = ArrayCount(remoteResources) DOWNTO 1 IF remoteResources[i].ownerId = peerId THEN ArrayDelete(remoteResources, i) count++ END END RETURN count END // Obtém estatísticas dos recursos PROCEDURE GetStatistics() : JSON stats is JSON // Contagens básicas stats.totalLocalResources = ArrayCount(localResources) stats.totalRemoteResources = ArrayCount(remoteResources) // Tamanho total dos recursos locais localSize is int8 = 0 FOR EACH resource OF localResources localSize += resource.size END stats.totalLocalSize = localSize // Formata o tamanho para exibição stats.formattedLocalSize = FormatFileSize(localSize) RETURN stats END // Formata tamanho de arquivo para exibição amigável PROCEDURE FormatFileSize(size is int8) : string IF size < 1024 THEN RETURN size + " B" ELSE IF size < 1024 * 1024 THEN RETURN Round(size / 1024, 2) + " KB" ELSE IF size < 1024 * 1024 * 1024 THEN RETURN Round(size / (1024 * 1024), 2) + " MB" ELSE RETURN Round(size / (1024 * 1024 * 1024), 2) + " GB" END END END ``` //############################## //############################## ``` // CLASSE: P2PNetworkManager - Gerencia a rede peer-to-peer Class P2PNetworkManager // Identificação do nó nodeId is string // ID único deste nó nodeName is string // Nome amigável // Sockets e portas serverSocket is Socket // Socket servidor listenPort is int // Porta para escuta discoveryPort is int // Porta para descoberta de peers // Listas de peers peers is array of Peer // Lista de peers conhecidos // Estado da rede isRunning is boolean = False // Indica se o servidor está rodando // Referências config is Config // Configurações logger is Logger // Sistema de logs resources is ResourceManager // Gerenciador de recursos // Timeouts connectionTimeout is int = 5000 // Timeout para conexão (ms) // Eventos PROCEDURE onPeerConnected(peer is Peer) // Evento: Peer conectado PROCEDURE onPeerDisconnected(peer is Peer) // Evento: Peer desconectado PROCEDURE onMessageReceived(message is P2PMessage, peer is Peer) // Evento: Mensagem recebida // Construtor PROCEDURE CONSTRUCTOR(id is string, name is string, cfg is Config, log is Logger, resourceMgr is ResourceManager) // Inicializa campos nodeId = id nodeName = name config = cfg logger = log resources = resourceMgr // Configura portas listenPort = config.GetPort() discoveryPort = config.GetDiscoveryPort() // Configura timeout connectionTimeout = config.GetConnectionTimeout() logger.Info("P2PNetworkManager inicializado: " + nodeName) END // Inicia o servidor PROCEDURE Start() : boolean // Verifica se já está rodando IF isRunning THEN logger.Warning("Servidor já está rodando") RETURN False END // Cria o socket servidor serverSocket = new Socket // Cria socket TCP IF NOT serverSocket.Create(SocketIP, listenPort) THEN logger.Error("Falha ao criar socket servidor na porta " + listenPort) RETURN False END // Marca como rodando isRunning = True // Inicia thread para aceitar conexões ThreadExecute(ThreadAcceptConnections, threadNormal) // Inicia thread de heartbeat para manter conexões ThreadExecute(ThreadHeartbeat, threadNormal) // Inicia descoberta de peers, se habilitada IF config.IsDiscoveryEnabled() THEN ThreadExecute(ThreadDiscovery, threadNormal) END // Conecta a peers conhecidos ConnectToKnownPeers() logger.Info("Servidor P2P iniciado na porta " + listenPort) RETURN True END // Para o servidor PROCEDURE Stop() : boolean // Verifica se está rodando IF NOT isRunning THEN logger.Warning("Servidor não está rodando") RETURN False END // Marca como não rodando para parar threads isRunning = False // Fecha socket servidor IF serverSocket <> Null AND serverSocket..Valid THEN serverSocket.Close() END // Fecha todas as conexões FOR EACH peer OF peers IF peer.IsConnected() THEN // Envia mensagem de despedida SendGoodbye(peer) // Fecha a conexão peer.CloseConnection() END END logger.Info("Servidor P2P parado") RETURN True END // Thread para aceitar conexões THREAD PROCEDURE ThreadAcceptConnections() logger.Debug("Thread de aceitação de conexões iniciada") WHILE isRunning // Aguarda por uma nova conexão IF serverSocket <> Null AND serverSocket..Valid THEN IF serverSocket.WaitForConnection(1000) THEN newSocket is Socket = serverSocket.WaitConnection() IF newSocket..Valid THEN // Define timeout para recebimento newSocket.Timeout = connectionTimeout // Inicia thread para processar esta conexão ThreadExecute(ThreadHandleConnection, threadNormal, newSocket) logger.Debug("Nova conexão recebida de: " + newSocket..RemoteAddress) END END END // Pequena pausa para não sobrecarregar a CPU Delay(100) END logger.Debug("Thread de aceitação de conexões finalizada") END // Thread para processar uma conexão THREAD PROCEDURE ThreadHandleConnection(socket is Socket) // Guarda o endereço para logs enderecoRemoto is string = socket..RemoteAddress logger.Debug("Processando nova conexão de " + enderecoRemoto) // Aguarda mensagem de hello helloReceived is boolean = False peerId is string = "" // Define o timeout para a mensagem inicial startTime is datetime = Now() WHILE DateDifference(startTime, Now(), dtSecond) < (connectionTimeout / 1000) // Verifica se há dados disponíveis IF socket.WaitForData(100) THEN // Recebe a mensagem messageData is Buffer = socket.Receive() IF messageData <> "" THEN // Tenta deserializar a mensagem message is P2PMessage(0, "") IF message.Deserialize(messageData) THEN // Verifica se é uma mensagem de hello IF message.type = P2PMessage.TYPE_HELLO THEN // Extrai payload payload is JSON = message.GetJSONPayload() IF payload <> Null THEN // Verifica campos necessários IF payload.id <> Null AND payload.name <> Null THEN peerId = payload.id // Processa a mensagem de hello ProcessHelloMessage(socket, payload) helloReceived = True Break END END END END END END // Verifica se o servidor ainda está rodando IF NOT isRunning THEN socket.Close() RETURN END // Pequena pausa Delay(50) END // Se não recebeu hello em tempo hábil, fecha a conexão IF NOT helloReceived THEN logger.Warning("Timeout esperando hello de " + enderecoRemoto + ", fechando conexão") socket.Close() RETURN END // Processa mensagens desta conexão ProcessMessages(socket, peerId) END // Processa uma mensagem de hello PROCEDURE ProcessHelloMessage(socket is Socket, payload is JSON) peerId is string = payload.id peerName is string = payload.name peerAddress is string = socket..RemoteAddress // Verifica se o peer sou eu mesmo (conexão loop) IF peerId = nodeId THEN logger.Warning("Conexão loop detectada, fechando conexão") socket.Close() RETURN END // Verifica se já conhecemos este peer existingPeer is boolean = False peerIndex is int = 0 FOR i = 1 TO ArrayCount(peers) IF peers[i].id = peerId THEN existingPeer = True peerIndex = i Break END END // Peer para callback callbackPeer is Peer = Null IF existingPeer THEN // Atualiza informações do peer peers[peerIndex].name = peerName peers[peerIndex].socket = socket peers[peerIndex].UpdateStatus(Peer.STATUS_CONNECTED) callbackPeer = peers[peerIndex] logger.Info("Peer reconectado: " + peerName + " (" + peerId + ")") ELSE // Cria novo peer newPeer is Peer(peerId, peerName, peerAddress) newPeer.socket = socket newPeer.status = Peer.STATUS_CONNECTED // Adiciona à lista ArrayAdd(peers, newPeer) callbackPeer = newPeer logger.Info("Novo peer conectado: " + peerName + " (" + peerId + ")") END // Envia resposta de hello SendHello(socket) // Envia lista de recursos SendResourceList(callbackPeer) // Notifica sobre a conexão IF onPeerConnected <> Null THEN onPeerConnected(callbackPeer) END END // Processa mensagens de um peer PROCEDURE ProcessMessages(socket is Socket, peerId is string) // Procura o peer na lista peer is Peer = FindPeerById(peerId) IF peer = Null THEN logger.Warning("Processando mensagens para peer não encontrado: " + peerId) socket.Close() RETURN END logger.Debug("Iniciando processamento de mensagens para: " + peer.name) // Loop principal de processamento WHILE isRunning AND socket..Estado = socketConectado // Verifica se há dados disponíveis IF socket.WaitForData(500) THEN // Recebe a mensagem messageData is Buffer = socket.Receive() IF messageData <> "" THEN // Atualiza timestamp de último contato peer.lastSeen = Now() // Tenta deserializar a mensagem message is P2PMessage(0, "") IF message.Deserialize(messageData) THEN // Processa a mensagem HandleMessage(message, peer) ELSE logger.Warning("Falha ao deserializar mensagem de " + peer.name) END END END // Verifica se o servidor ainda está rodando IF NOT isRunning THEN peer.CloseConnection() RETURN END // Pequena pausa para não sobrecarregar a CPU Delay(10) END // Marca o peer como desconectado peer.UpdateStatus(Peer.STATUS_DISCONNECTED) // Notifica sobre a desconexão IF onPeerDisconnected <> Null THEN onPeerDisconnected(peer) END logger.Info("Conexão encerrada com peer: " + peer.name) END // Processa mensagem recebida PROCEDURE HandleMessage(message is P2PMessage, peer is Peer) // Notifica sobre a mensagem recebida IF onMessageReceived <> Null THEN onMessageReceived(message, peer) END // Processa com base no tipo SWITCH message.type CASE P2PMessage.TYPE_GOODBYE: // Peer está se despedindo logger.Info("Peer " + peer.name + " enviou mensagem de despedida") peer.CloseConnection() // Notifica sobre a desconexão IF onPeerDisconnected <> Null THEN onPeerDisconnected(peer) END CASE P2PMessage.TYPE_PING: // Responde com pong SendPong(peer) CASE P2PMessage.TYPE_RESOURCE_LIST: // Atualiza lista de recursos do peer ProcessResourceList(message, peer) CASE P2PMessage.TYPE_RESOURCE_REQUEST: // Processa solicitação de recurso ProcessResourceRequest(message, peer) CASE P2PMessage.TYPE_SEARCH: // Processa busca de recursos ProcessSearchRequest(message, peer) CASE P2PMessage.TYPE_DATA_TRANSFER: // Processa transferência de dados ProcessDataTransfer(message, peer) DEFAULT: logger.Debug("Mensagem de tipo desconhecido recebida: " + message.type) END END // Thread de heartbeat para manter conexões THREAD PROCEDURE ThreadHeartbeat() logger.Debug("Thread de heartbeat iniciada") WHILE isRunning // Ping para todos os peers conectados FOR EACH peer OF peers IF peer.IsConnected() THEN // Verifica tempo desde último contato elapsedTime is int = DateDifference(peer.lastSeen, Now(), dtSecond) // Se passou mais de 30 segundos, envia ping IF elapsedTime > 30 THEN SendPing(peer) END END END // Aguarda 10 segundos antes de próxima verificação sleepTime is int = 10 FOR i = 1 TO sleepTime IF NOT isRunning THEN Break END Delay(1000) END END logger.Debug("Thread de heartbeat finalizada") END // Thread de descoberta de peers THREAD PROCEDURE ThreadDiscovery() logger.Debug("Thread de descoberta iniciada") // Configura socket UDP para discovery discoverySocket is Socket IF NOT discoverySocket.Create(SocketDgram, discoveryPort) THEN logger.Error("Falha ao criar socket de descoberta na porta " + discoveryPort) RETURN END // Envia anúncio inicial SendDiscoveryAnnouncement(discoverySocket) // Loop principal de descoberta WHILE isRunning // Verifica se há dados de descoberta IF discoverySocket.WaitForData(1000) THEN // Recebe anúncio message is Buffer senderAddress is string discoverySocket.ReceiveFrom(message, senderAddress) IF message <> "" THEN ProcessDiscoveryMessage(message, senderAddress) END END // A cada 60 segundos, envia novo anúncio STATIC lastAnnouncement is datetime = Now() IF DateDifference(lastAnnouncement, Now(), dtSecond) > 60 THEN SendDiscoveryAnnouncement(discoverySocket) lastAnnouncement = Now() END // Pequena pausa Delay(100) END // Fecha socket de descoberta discoverySocket.Close() logger.Debug("Thread de descoberta finalizada") END // Envia anúncio de descoberta PROCEDURE SendDiscoveryAnnouncement(socket is Socket) // Prepara a mensagem announcement is JSON announcement.id = nodeId announcement.name = nodeName announcement.port = listenPort // Serializa para envio message is string = JSONToString(announcement) // Envia para endereço de broadcast socket.SendTo(message, "255.255.255.255:" + discoveryPort) logger.Debug("Anúncio de descoberta enviado") END // Processa mensagem de descoberta PROCEDURE ProcessDiscoveryMessage(message is Buffer, senderAddress is string) TRY // Parse da mensagem announcement is JSON = JSONParse(message) // Verifica campos obrigatórios IF announcement.id <> Null AND announcement.name <> Null AND announcement.port <> Null THEN // Ignora nosso próprio anúncio IF announcement.id = nodeId THEN RETURN END peerId is string = announcement.id peerName is string = announcement.name peerPort is int = announcement.port // Extrai IP do endereço de origem parts is array of strings = Split(senderAddress, ":") peerIP is string = parts[1] // Monta endereço de conexão peerAddress is string = peerIP + ":" + peerPort logger.Debug("Anúncio de descoberta recebido de " + peerName + " em " + peerAddress) // Verifica se já conhecemos este peer peerConhecido is boolean = False FOR EACH peer OF peers IF peer.id = peerId THEN peerConhecido = True // Se estiver desconectado, tenta reconectar IF NOT peer.IsConnected() THEN // Atualiza endereço, pode ter mudado peer.address = peerAddress // Inicia conexão em thread separada ThreadExecute(ThreadConnect, threadNormal, peer) END Break END END // Se não conhecemos, adiciona e tenta conectar IF NOT peerConhecido THEN // Cria novo peer newPeer is Peer(peerId, peerName, peerAddress) // Adiciona à lista ArrayAdd(peers, newPeer) // Inicia conexão em thread separada ThreadExecute(ThreadConnect, threadNormal, newPeer) END END CATCH logger.Warning("Erro ao processar mensagem de descoberta: " + ErrorInfo()) END END // Thread para conectar a um peer THREAD PROCEDURE ThreadConnect(peer is Peer) logger.Debug("Iniciando conexão com peer " + peer.name + " em " + peer.address) // Marca como conectando peer.UpdateStatus(Peer.STATUS_CONNECTING) // Cria socket TCP socket is Socket IF NOT socket.Create(SocketIP) THEN logger.Error("Falha ao criar socket cliente para " + peer.address) peer.UpdateStatus(Peer.STATUS_FAILED) RETURN END // Tenta conectar IF NOT socket.Connect(peer.address, connectionTimeout) THEN logger.Warning("Falha ao conectar a " + peer.address) socket.Close() peer.UpdateStatus(Peer.STATUS_FAILED) RETURN END // Envia mensagem de hello SendHello(socket) // Aguarda resposta helloReceived is boolean = False startTime is datetime = Now() WHILE DateDifference(startTime, Now(), dtSecond) < (connectionTimeout / 1000) // Verifica se há dados disponíveis IF socket.WaitForData(100) THEN // Recebe a mensagem messageData is Buffer = socket.Receive() IF messageData <> "" THEN // Tenta deserializar a mensagem message is P2PMessage(0, "") IF message.Deserialize(messageData) THEN // Verifica se é uma mensagem de hello IF message.type = P2PMessage.TYPE_HELLO THEN // Extrai payload payload is JSON = message.GetJSONPayload() IF payload <> Null THEN // Verifica campos necessários IF payload.id <> Null AND payload.name <> Null AND payload.id = peer.id THEN // Atualiza informações do peer peer.name = payload.name peer.socket = socket peer.UpdateStatus(Peer.STATUS_CONNECTED) // Envia lista de recursos SendResourceList(peer) // Notifica sobre a conexão IF onPeerConnected <> Null THEN onPeerConnected(peer) END helloReceived = True // Processa mensagens desta conexão ProcessMessages(socket, peer.id) RETURN END END END END END END // Pequena pausa Delay(50) END // Se não recebeu hello, fecha a conexão IF NOT helloReceived THEN logger.Warning("Timeout esperando hello de " + peer.address) socket.Close() peer.UpdateStatus(Peer.STATUS_FAILED) END END ////————— Vamos continuar a implementação do ResourceManager e demais classes necessárias para concluir o projeto WNetShare. //############################## ``` // Remove um recurso local PROCEDURE RemoveLocalResource(resourceId is string) : boolean // Procura o recurso na lista de recursos locais FOR i = 1 TO ArrayCount(localResources) IF localResources[i].id = resourceId THEN // Remove da lista ArrayDelete(localResources, i) // Persiste alterações SaveResources() logger.Info("Recurso local removido: " + resourceId) RETURN True END END logger.Warning("Recurso local não encontrado para remoção: " + resourceId) RETURN False END // Remove um recurso remoto PROCEDURE RemoveRemoteResource(resourceId is string) : boolean // Procura o recurso na lista de recursos remotos FOR i = 1 TO ArrayCount(remoteResources) IF remoteResources[i].id = resourceId THEN // Remove da lista ArrayDelete(remoteResources, i) logger.Info("Recurso remoto removido: " + resourceId) RETURN True END END logger.Debug("Recurso remoto não encontrado para remoção: " + resourceId) RETURN False END // Obtém um recurso pelo ID PROCEDURE GetResource(resourceId is string, localOnly is boolean = False) : FileResource // Procura nos recursos locais FOR EACH resource OF localResources IF resource.id = resourceId THEN RETURN resource END END // Se localOnly, não procura nos remotos IF localOnly THEN RETURN Null END // Procura nos recursos remotos FOR EACH resource OF remoteResources IF resource.id = resourceId THEN RETURN resource END END // Não encontrado RETURN Null END // Pesquisa recursos por nome PROCEDURE SearchResources(searchTerm is string, localOnly is boolean = False) : array of FileResource results is array of FileResource searchTermLower is string = Lower(searchTerm) // Função auxiliar para verificar correspondência FUNCTION CheckMatch(resource is FileResource) : boolean IF Contains(Lower(resource.name), searchTermLower) THEN RETURN True END RETURN False END // Procura nos recursos locais FOR EACH resource OF localResources IF CheckMatch(resource) THEN ArrayAdd(results, resource) END END // Se localOnly, não procura nos remotos IF localOnly THEN RETURN results END // Procura nos recursos remotos FOR EACH resource OF remoteResources IF CheckMatch(resource) THEN ArrayAdd(results, resource) END END RETURN results END // Verifica se uma string contém outra PRIVATE PROCEDURE Contains(text is string, searchTerm is string) : boolean RETURN (Position(text, searchTerm) > 0) END // Salva recursos locais em arquivo PROCEDURE SaveResources() : boolean TRY // Criamos um array com as strings serializadas dos recursos serializedResources is array of string FOR EACH resource OF localResources serialized is string = resource.Serialize() IF serialized <> "" THEN ArrayAdd(serializedResources, serialized) END END // Prepara dados para salvar data is JSON data.resources = serializedResources // Define caminho do arquivo filePath is string = resourceDir + "\resources.json" // Garante que o diretório existe IF NOT fDirExist(resourceDir) THEN IF NOT fMakeDir(resourceDir) THEN logger.Error("Falha ao criar diretório de recursos: " + resourceDir) RETURN False END END // Salva o arquivo IF fSaveText(filePath, JSONToString(data)) THEN logger.Debug("Recursos salvos: " + ArrayCount(serializedResources) + " recursos") RETURN True ELSE logger.Error("Falha ao salvar recursos em: " + filePath) RETURN False END CATCH logger.Error("Erro ao salvar recursos: " + ErrorInfo()) RETURN False END END // Carrega recursos locais de arquivo PROCEDURE LoadResources() : boolean // Define caminho do arquivo filePath is string = resourceDir + "\resources.json" // Verifica se o arquivo existe IF NOT fFileExist(filePath) THEN logger.Info("Arquivo de recursos não encontrado: " + filePath) RETURN True // Não é erro, apenas não há recursos ainda END TRY // Lê o arquivo content is string = fLoadText(filePath) IF content = "" THEN logger.Warning("Arquivo de recursos vazio") RETURN True END // Faz o parse do JSON data is JSON = JSONParse(content) // Limpa a lista atual localResources = new array of FileResource // Deserializa cada recurso FOR EACH serialized OF data.resources resource is FileResource("", "", "", "") IF resource.Deserialize(serialized) THEN // Verifica se ainda existe o arquivo IF resource.CheckAvailability() THEN ArrayAdd(localResources, resource) ELSE logger.Warning("Arquivo não disponível para o recurso: " + resource.name) END ELSE logger.Warning("Falha ao deserializar recurso") END END logger.Info("Recursos carregados: " + ArrayCount(localResources) + " recursos") RETURN True CATCH logger.Error("Erro ao carregar recursos: " + ErrorInfo()) RETURN False END END // Gera lista de recursos para compartilhar PROCEDURE GenerateResourceList() : string data is JSON resources is array of JSON FOR EACH resource OF localResources // Verifica se o recurso ainda está disponível IF resource.CheckAvailability() THEN res is JSON res.id = resource.id res.name = resource.name res.size = resource.size res.hash = resource.hash res.mimeType = resource.mimeType ArrayAdd(resources, res) END END data.resources = resources RETURN JSONToString(data) END // Atualiza lista de recursos remotos de um peer PROCEDURE UpdateRemoteResources(peerId is string, peerName is string, resourceList is string) : int IF resourceList = "" THEN RETURN 0 END // Remove recursos atuais deste peer RemoveResourcesFromPeer(peerId) // Faz parse da lista TRY data is JSON = JSONParse(resourceList) addedCount is int = 0 FOR EACH resData OF data.resources // Cria o recurso resource is FileResource(resData.name, "", peerId, peerName) resource.id = resData.id resource.size = resData.size resource.hash = resData.hash resource.mimeType = resData.mimeType // Adiciona à lista IF AddRemoteResource(resource) THEN addedCount++ END END logger.Info("Atualizada lista de recursos de " + peerName + ": " + addedCount + " recursos") RETURN addedCount CATCH logger.Error("Erro ao processar lista de recursos: " + ErrorInfo()) RETURN 0 END END // Remove recursos de um peer específico PROCEDURE RemoveResourcesFromPeer(peerId is string) : int count is int = 0 // Remove todos os recursos deste peer FOR i = ArrayCount(remoteResources) DOWNTO 1 IF remoteResources[i].ownerId = peerId THEN ArrayDelete(remoteResources, i) count++ END END RETURN count END // Obtém estatísticas dos recursos PROCEDURE GetStatistics() : JSON stats is JSON // Contagens básicas stats.totalLocalResources = ArrayCount(localResources) stats.totalRemoteResources = ArrayCount(remoteResources) // Tamanho total dos recursos locais localSize is int8 = 0 FOR EACH resource OF localResources localSize += resource.size END stats.totalLocalSize = localSize // Formata o tamanho para exibição stats.formattedLocalSize = FormatFileSize(localSize) RETURN stats END // Formata tamanho de arquivo para exibição amigável PROCEDURE FormatFileSize(size is int8) : string IF size < 1024 THEN RETURN size + " B" ELSE IF size < 1024 * 1024 THEN RETURN Round(size / 1024, 2) + " KB" ELSE IF size < 1024 * 1024 * 1024 THEN RETURN Round(size / (1024 * 1024), 2) + " MB" ELSE RETURN Round(size / (1024 * 1024 * 1024), 2) + " GB" END END END ``` //############################## //############################## ``` // CLASSE: P2PNetworkManager - Gerencia a rede peer-to-peer Class P2PNetworkManager // Identificação do nó nodeId is string // ID único deste nó nodeName is string // Nome amigável // Sockets e portas serverSocket is Socket // Socket servidor listenPort is int // Porta para escuta discoveryPort is int // Porta para descoberta de peers // Listas de peers peers is array of Peer // Lista de peers conhecidos // Estado da rede isRunning is boolean = False // Indica se o servidor está rodando // Referências config is Config // Configurações logger is Logger // Sistema de logs resources is ResourceManager // Gerenciador de recursos // Timeouts connectionTimeout is int = 5000 // Timeout para conexão (ms) // Eventos PROCEDURE onPeerConnected(peer is Peer) // Evento: Peer conectado PROCEDURE onPeerDisconnected(peer is Peer) // Evento: Peer desconectado PROCEDURE onMessageReceived(message is P2PMessage, peer is Peer) // Evento: Mensagem recebida // Construtor PROCEDURE CONSTRUCTOR(id is string, name is string, cfg is Config, log is Logger, resourceMgr is ResourceManager) // Inicializa campos nodeId = id nodeName = name config = cfg logger = log resources = resourceMgr // Configura portas listenPort = config.GetPort() discoveryPort = config.GetDiscoveryPort() // Configura timeout connectionTimeout = config.GetConnectionTimeout() logger.Info("P2PNetworkManager inicializado: " + nodeName) END // Inicia o servidor PROCEDURE Start() : boolean // Verifica se já está rodando IF isRunning THEN logger.Warning("Servidor já está rodando") RETURN False END // Cria o socket servidor serverSocket = new Socket // Cria socket TCP IF NOT serverSocket.Create(SocketIP, listenPort) THEN logger.Error("Falha ao criar socket servidor na porta " + listenPort) RETURN False END // Marca como rodando isRunning = True // Inicia thread para aceitar conexões ThreadExecute(ThreadAcceptConnections, threadNormal) // Inicia thread de heartbeat para manter conexões ThreadExecute(ThreadHeartbeat, threadNormal) // Inicia descoberta de peers, se habilitada IF config.IsDiscoveryEnabled() THEN ThreadExecute(ThreadDiscovery, threadNormal) END // Conecta a peers conhecidos ConnectToKnownPeers() logger.Info("Servidor P2P iniciado na porta " + listenPort) RETURN True END // Para o servidor PROCEDURE Stop() : boolean // Verifica se está rodando IF NOT isRunning THEN logger.Warning("Servidor não está rodando") RETURN False END // Marca como não rodando para parar threads isRunning = False // Fecha socket servidor IF serverSocket <> Null AND serverSocket..Valid THEN serverSocket.Close() END // Fecha todas as conexões FOR EACH peer OF peers IF peer.IsConnected() THEN // Envia mensagem de despedida SendGoodbye(peer) // Fecha a conexão peer.CloseConnection() END END logger.Info("Servidor P2P parado") RETURN True END // Thread para aceitar conexões THREAD PROCEDURE ThreadAcceptConnections() logger.Debug("Thread de aceitação de conexões iniciada") WHILE isRunning // Aguarda por uma nova conexão IF serverSocket <> Null AND serverSocket..Valid THEN IF serverSocket.WaitForConnection(1000) THEN newSocket is Socket = serverSocket.WaitConnection() IF newSocket..Valid THEN // Define timeout para recebimento newSocket.Timeout = connectionTimeout // Inicia thread para processar esta conexão ThreadExecute(ThreadHandleConnection, threadNormal, newSocket) logger.Debug("Nova conexão recebida de: " + newSocket..RemoteAddress) END END END // Pequena pausa para não sobrecarregar a CPU Delay(100) END logger.Debug("Thread de aceitação de conexões finalizada") END // Thread para processar uma conexão THREAD PROCEDURE ThreadHandleConnection(socket is Socket) // Guarda o endereço para logs enderecoRemoto is string = socket..RemoteAddress logger.Debug("Processando nova conexão de " + enderecoRemoto) // Aguarda mensagem de hello helloReceived is boolean = False peerId is string = "" // Define o timeout para a mensagem inicial startTime is datetime = Now() WHILE DateDifference(startTime, Now(), dtSecond) < (connectionTimeout / 1000) // Verifica se há dados disponíveis IF socket.WaitForData(100) THEN // Recebe a mensagem messageData is Buffer = socket.Receive() IF messageData <> "" THEN // Tenta deserializar a mensagem message is P2PMessage(0, "") IF message.Deserialize(messageData) THEN // Verifica se é uma mensagem de hello IF message.type = P2PMessage.TYPE_HELLO THEN // Extrai payload payload is JSON = message.GetJSONPayload() IF payload <> Null THEN // Verifica campos necessários IF payload.id <> Null AND payload.name <> Null THEN peerId = payload.id // Processa a mensagem de hello ProcessHelloMessage(socket, payload) helloReceived = True Break END END END END END END // Verifica se o servidor ainda está rodando IF NOT isRunning THEN socket.Close() RETURN END // Pequena pausa Delay(50) END // Se não recebeu hello em tempo hábil, fecha a conexão IF NOT helloReceived THEN logger.Warning("Timeout esperando hello de " + enderecoRemoto + ", fechando conexão") socket.Close() RETURN END // Processa mensagens desta conexão ProcessMessages(socket, peerId) END // Processa uma mensagem de hello PROCEDURE ProcessHelloMessage(socket is Socket, payload is JSON) peerId is string = payload.id peerName is string = payload.name peerAddress is string = socket..RemoteAddress // Verifica se o peer sou eu mesmo (conexão loop) IF peerId = nodeId THEN logger.Warning("Conexão loop detectada, fechando conexão") socket.Close() RETURN END // Verifica se já conhecemos este peer existingPeer is boolean = False peerIndex is int = 0 FOR i = 1 TO ArrayCount(peers) IF peers[i].id = peerId THEN existingPeer = True peerIndex = i Break END END // Peer para callback callbackPeer is Peer = Null IF existingPeer THEN // Atualiza informações do peer peers[peerIndex].name = peerName peers[peerIndex].socket = socket peers[peerIndex].UpdateStatus(Peer.STATUS_CONNECTED) callbackPeer = peers[peerIndex] logger.Info("Peer reconectado: " + peerName + " (" + peerId + ")") ELSE // Cria novo peer newPeer is Peer(peerId, peerName, peerAddress) newPeer.socket = socket newPeer.status = Peer.STATUS_CONNECTED // Adiciona à lista ArrayAdd(peers, newPeer) callbackPeer = newPeer logger.Info("Novo peer conectado: " + peerName + " (" + peerId + ")") END // Envia resposta de hello SendHello(socket) // Envia lista de recursos SendResourceList(callbackPeer) // Notifica sobre a conexão IF onPeerConnected <> Null THEN onPeerConnected(callbackPeer) END END // Processa mensagens de um peer PROCEDURE ProcessMessages(socket is Socket, peerId is string) // Procura o peer na lista peer is Peer = FindPeerById(peerId) IF peer = Null THEN logger.Warning("Processando mensagens para peer não encontrado: " + peerId) socket.Close() RETURN END logger.Debug("Iniciando processamento de mensagens para: " + peer.name) // Loop principal de processamento WHILE isRunning AND socket..Estado = socketConectado // Verifica se há dados disponíveis IF socket.WaitForData(500) THEN // Recebe a mensagem messageData is Buffer = socket.Receive() IF messageData <> "" THEN // Atualiza timestamp de último contato peer.lastSeen = Now() // Tenta deserializar a mensagem message is P2PMessage(0, "") IF message.Deserialize(messageData) THEN // Processa a mensagem HandleMessage(message, peer) ELSE logger.Warning("Falha ao deserializar mensagem de " + peer.name) END END END // Verifica se o servidor ainda está rodando IF NOT isRunning THEN peer.CloseConnection() RETURN END // Pequena pausa para não sobrecarregar a CPU Delay(10) END // Marca o peer como desconectado peer.UpdateStatus(Peer.STATUS_DISCONNECTED) // Notifica sobre a desconexão IF onPeerDisconnected <> Null THEN onPeerDisconnected(peer) END logger.Info("Conexão encerrada com peer: " + peer.name) END // Processa mensagem recebida PROCEDURE HandleMessage(message is P2PMessage, peer is Peer) // Notifica sobre a mensagem recebida IF onMessageReceived <> Null THEN onMessageReceived(message, peer) END // Processa com base no tipo SWITCH message.type CASE P2PMessage.TYPE_GOODBYE: // Peer está se despedindo logger.Info("Peer " + peer.name + " enviou mensagem de despedida") peer.CloseConnection() // Notifica sobre a desconexão IF onPeerDisconnected <> Null THEN onPeerDisconnected(peer) END CASE P2PMessage.TYPE_PING: // Responde com pong SendPong(peer) CASE P2PMessage.TYPE_RESOURCE_LIST: // Atualiza lista de recursos do peer ProcessResourceList(message, peer) CASE P2PMessage.TYPE_RESOURCE_REQUEST: // Processa solicitação de recurso ProcessResourceRequest(message, peer) CASE P2PMessage.TYPE_SEARCH: // Processa busca de recursos ProcessSearchRequest(message, peer) CASE P2PMessage.TYPE_DATA_TRANSFER: // Processa transferência de dados ProcessDataTransfer(message, peer) DEFAULT: logger.Debug("Mensagem de tipo desconhecido recebida: " + message.type) END END // Thread de heartbeat para manter conexões THREAD PROCEDURE ThreadHeartbeat() logger.Debug("Thread de heartbeat iniciada") WHILE isRunning // Ping para todos os peers conectados FOR EACH peer OF peers IF peer.IsConnected() THEN // Verifica tempo desde último contato elapsedTime is int = DateDifference(peer.lastSeen, Now(), dtSecond) // Se passou mais de 30 segundos, envia ping IF elapsedTime > 30 THEN SendPing(peer) END END END // Aguarda 10 segundos antes de próxima verificação sleepTime is int = 10 FOR i = 1 TO sleepTime IF NOT isRunning THEN Break END Delay(1000) END END logger.Debug("Thread de heartbeat finalizada") END // Thread de descoberta de peers THREAD PROCEDURE ThreadDiscovery() logger.Debug("Thread de descoberta iniciada") // Configura socket UDP para discovery discoverySocket is Socket IF NOT discoverySocket.Create(SocketDgram, discoveryPort) THEN logger.Error("Falha ao criar socket de descoberta na porta " + discoveryPort) RETURN END // Envia anúncio inicial SendDiscoveryAnnouncement(discoverySocket) // Loop principal de descoberta WHILE isRunning // Verifica se há dados de descoberta IF discoverySocket.WaitForData(1000) THEN // Recebe anúncio message is Buffer senderAddress is string discoverySocket.ReceiveFrom(message, senderAddress) IF message <> "" THEN ProcessDiscoveryMessage(message, senderAddress) END END // A cada 60 segundos, envia novo anúncio STATIC lastAnnouncement is datetime = Now() IF DateDifference(lastAnnouncement, Now(), dtSecond) > 60 THEN SendDiscoveryAnnouncement(discoverySocket) lastAnnouncement = Now() END // Pequena pausa Delay(100) END // Fecha socket de descoberta discoverySocket.Close() logger.Debug("Thread de descoberta finalizada") END // Envia anúncio de descoberta PROCEDURE SendDiscoveryAnnouncement(socket is Socket) // Prepara a mensagem announcement is JSON announcement.id = nodeId announcement.name = nodeName announcement.port = listenPort // Serializa para envio message is string = JSONToString(announcement) // Envia para endereço de broadcast socket.SendTo(message, "255.255.255.255:" + discoveryPort) logger.Debug("Anúncio de descoberta enviado") END // Processa mensagem de descoberta PROCEDURE ProcessDiscoveryMessage(message is Buffer, senderAddress is string) TRY // Parse da mensagem announcement is JSON = JSONParse(message) // Verifica campos obrigatórios IF announcement.id <> Null AND announcement.name <> Null AND announcement.port <> Null THEN // Ignora nosso próprio anúncio IF announcement.id = nodeId THEN RETURN END peerId is string = announcement.id peerName is string = announcement.name peerPort is int = announcement.port // Extrai IP do endereço de origem parts is array of strings = Split(senderAddress, ":") peerIP is string = parts[1] // Monta endereço de conexão peerAddress is string = peerIP + ":" + peerPort logger.Debug("Anúncio de descoberta recebido de " + peerName + " em " + peerAddress) // Verifica se já conhecemos este peer peerConhecido is boolean = False FOR EACH peer OF peers IF peer.id = peerId THEN peerConhecido = True // Se estiver desconectado, tenta reconectar IF NOT peer.IsConnected() THEN // Atualiza endereço, pode ter mudado peer.address = peerAddress // Inicia conexão em thread separada ThreadExecute(ThreadConnect, threadNormal, peer) END Break END END // Se não conhecemos, adiciona e tenta conectar IF NOT peerConhecido THEN // Cria novo peer newPeer is Peer(peerId, peerName, peerAddress) // Adiciona à lista ArrayAdd(peers, newPeer) // Inicia conexão em thread separada ThreadExecute(ThreadConnect, threadNormal, newPeer) END END CATCH logger.Warning("Erro ao processar mensagem de descoberta: " + ErrorInfo()) END END // Thread para conectar a um peer THREAD PROCEDURE ThreadConnect(peer is Peer) logger.Debug("Iniciando conexão com peer " + peer.name + " em " + peer.address) // Marca como conectando peer.UpdateStatus(Peer.STATUS_CONNECTING) // Cria socket TCP socket is Socket IF NOT socket.Create(SocketIP) THEN logger.Error("Falha ao criar socket cliente para " + peer.address) peer.UpdateStatus(Peer.STATUS_FAILED) RETURN END // Tenta conectar IF NOT socket.Connect(peer.address, connectionTimeout) THEN logger.Warning("Falha ao conectar a " + peer.address) socket.Close() peer.UpdateStatus(Peer.STATUS_FAILED) RETURN END // Envia mensagem de hello SendHello(socket) // Aguarda resposta helloReceived is boolean = False startTime is datetime = Now() WHILE DateDifference(startTime, Now(), dtSecond) < (connectionTimeout / 1000) // Verifica se há dados disponíveis IF socket.WaitForData(100) THEN // Recebe a mensagem messageData is Buffer = socket.Receive() IF messageData <> "" THEN // Tenta deserializar a mensagem message is P2PMessage(0, "") IF message.Deserialize(messageData) THEN // Verifica se é uma mensagem de hello IF message.type = P2PMessage.TYPE_HELLO THEN // Extrai payload payload is JSON = message.GetJSONPayload() IF payload <> Null THEN // Verifica campos necessários IF payload.id <> Null AND payload.name <> Null AND payload.id = peer.id THEN // Atualiza informações do peer peer.name = payload.name peer.socket = socket peer.UpdateStatus(Peer.STATUS_CONNECTED) // Envia lista de recursos SendResourceList(peer) // Notifica sobre a conexão IF onPeerConnected <> Null THEN onPeerConnected(peer) END helloReceived = True // Processa mensagens desta conexão ProcessMessages(socket, peer.id) RETURN END END END END END END // Pequena pausa Delay(50) END // Se não recebeu hello, fecha a conexão IF NOT helloReceived THEN logger.Warning("Timeout esperando hello de " + peer.address) socket.Close() peer.UpdateStatus(Peer.STATUS_FAILED) END END ////————- Vamos continuar com a implementação da classe principal WNetShare para concluir o projeto: //############################## ``` // Configura callbacks para eventos PROCEDURE ConfigureCallbacks() // Configura callbacks do gerenciador de rede network.onMessageReceived = OnNetworkMessageReceived network.onPeerConnected = OnPeerConnected network.onPeerDisconnected = OnPeerDisconnected END // Inicia o sistema PROCEDURE Start() : boolean // Verifica se já está rodando IF isRunning THEN logger.Warning("Sistema já está rodando") RETURN False END // Inicia o gerenciador de rede IF NOT network.Start() THEN logger.Error("Falha ao iniciar gerenciador de rede") RETURN False END // Define estado como rodando isRunning = True logger.Info("WNetShare iniciado: " + nodeName + " (ID: " + nodeId + ")") RETURN True END // Para o sistema PROCEDURE Stop() : boolean // Verifica se está rodando IF NOT isRunning THEN logger.Warning("Sistema não está rodando") RETURN False END // Para o gerenciador de rede network.Stop() // Define estado como parado isRunning = False // Salva peers conhecidos network.SaveKnownPeers() logger.Info("WNetShare parado") RETURN True END // Compartilha um arquivo PROCEDURE ShareFile(filePath is string, name is string = "") : FileResource // Verifica se o sistema está rodando IF NOT isRunning THEN logger.Warning("Sistema não está rodando") RETURN Null END // Compartilha o arquivo resource is FileResource = resources.ShareFile(filePath, name) // Notifica peers sobre o novo recurso IF resource <> Null THEN // Atualiza todos os peers sobre a alteração nos recursos FOR EACH peer OF network.peers IF peer.IsConnected() THEN network.SendResourceList(peer) END END END RETURN resource END // Busca recursos na rede PROCEDURE Search(term is string) : array of FileResource // Verifica se o sistema está rodando IF NOT isRunning THEN logger.Warning("Sistema não está rodando") RETURN new array of FileResource END // Inicia busca na rede RETURN network.SearchNetwork(term) END // Solicita um recurso PROCEDURE RequestResource(resourceId is string, peerId is string) : boolean // Verifica se o sistema está rodando IF NOT isRunning THEN logger.Warning("Sistema não está rodando") RETURN False END // Solicita o recurso RETURN network.RequestResource(resourceId, peerId) END // Obtém estatísticas do sistema PROCEDURE GetStatistics() : JSON stats is JSON // Estatísticas de recursos resourceStats is JSON = resources.GetStatistics() // Estatísticas de rede networkStats is JSON networkStats.peersTotal = ArrayCount(network.peers) // Conta peers conectados peersConnected is int = 0 FOR EACH peer OF network.peers IF peer.IsConnected() THEN peersConnected++ END END networkStats.peersConnected = peersConnected // Combina estatísticas stats.resources = resourceStats stats.network = networkStats stats.nodeId = nodeId stats.nodeName = nodeName stats.isRunning = isRunning RETURN stats END // Callback: Mensagem recebida PROCEDURE OnNetworkMessageReceived(message is P2PMessage, peer is Peer) // Processa com base no tipo SWITCH message.type CASE P2PMessage.TYPE_SEARCH_RESULT: // Resultados de busca ProcessSearchResults(message, peer) END END // Processa resultados de busca PROCEDURE ProcessSearchResults(message is P2PMessage, peer is Peer) // Extrai informações payload is JSON = message.GetJSONPayload() IF payload = Null THEN RETURN END // Verifica campos necessários IF payload.term = Null OR payload.results = Null THEN logger.Warning("Resultado de busca inválido") RETURN END term is string = payload.term resultItems is array of JSON = payload.results // Converte para array de recursos results is array of FileResource FOR EACH item OF resultItems resource is FileResource(item.name, "", peer.id, peer.name) resource.id = item.id resource.size = item.size resource.hash = item.hash resource.mimeType = item.mimeType ArrayAdd(results, resource) END // Notifica sobre resultados de busca IF onSearchResults <> Null THEN onSearchResults(term, results, peer) END logger.Info("Recebidos " + ArrayCount(results) + " resultados de busca de " + peer.name + " para: " + term) END // Callback: Peer conectado PROCEDURE OnPeerConnected(peer is Peer) logger.Info("Peer conectado: " + peer.name + " (" + peer.address + ")") END // Callback: Peer desconectado PROCEDURE OnPeerDisconnected(peer is Peer) logger.Info("Peer desconectado: " + peer.name) END END ``` //############################## //############################## ``` // PROCEDIMENTO PRINCIPAL: Inicializa e executa o sistema Procedure WNetShareMain() // Banner de inicialização Trace([ =================================================== WNetShare - Sistema P2P de Compartilhamento Seguro Versão 2.0 =================================================== ]) // Inicializa o sistema wnetshare is WNetShare // Mostra informações iniciais Trace("Inicializando WNetShare como: " + wnetshare.nodeName) Trace("ID do nó: " + wnetshare.nodeId) // Inicia o sistema IF wnetshare.Start() THEN Trace("Sistema iniciado com sucesso") // Exibe informações de portas Trace("Porta principal: " + wnetshare.config.GetPort()) Trace("Porta de descoberta: " + wnetshare.config.GetDiscoveryPort()) // Exibe diretórios Trace("Diretório de recursos: " + wnetshare.resources.resourceDir) Trace("Diretório de downloads: " + wnetshare.resources.downloadDir) // Aqui seria o ponto para iniciar uma interface de usuário // ou expor um serviço web para controle do sistema // Para demonstração, compartilha um arquivo exemplo IF fFileExist(fCurrentDir() + "\exemplo.txt") THEN Trace("Compartilhando arquivo de exemplo...") wnetshare.ShareFile(fCurrentDir() + "\exemplo.txt") ELSE // Cria um arquivo de exemplo fSaveText(fCurrentDir() + "\exemplo.txt", "Este é um arquivo de exemplo do WNetShare") Trace("Criado e compartilhado arquivo de exemplo") wnetshare.ShareFile(fCurrentDir() + "\exemplo.txt") END // Aguarda entrada do usuário para encerrar Trace([ Sistema WNetShare em execução. Digite 'exit' para encerrar. ]) // Loop simples para manter o sistema rodando // Em uma aplicação real, este loop seria gerenciado pela interface de usuário sair is boolean = False WHILE NOT sair comando is string = InKey() IF Lower(comando) = "exit" THEN sair = True END Delay(100) END // Para o sistema Trace("Encerrando WNetShare...") wnetshare.Stop() ELSE Trace("Falha ao iniciar o sistema") END Trace("Sistema encerrado") END ``` //############################## //############################## ``` // INTERFACE DE USUÁRIO: Interface básica para o WNetShare // Tela principal Window WIN_WNetShareMain // Referência ao sistema wnetshare is WNetShare // Interface PROCEDURE Inicializar() // Inicializa o sistema wnetshare = new WNetShare // Configura callbacks para atualizar interface wnetshare.onSearchResults = OnSearchResults wnetshare.onResourceReceived = OnResourceReceived // Atualiza informações na interface AtualizarInterface() END // Inicia o sistema PROCEDURE Iniciar() IF NOT wnetshare.isRunning THEN IF wnetshare.Start() THEN Message("Sistema iniciado com sucesso", "WNetShare") AtualizarInterface() ELSE Error("Falha ao iniciar o sistema", "WNetShare") END ELSE Info("Sistema já está em execução", "WNetShare") END END // Para o sistema PROCEDURE Parar() IF wnetshare.isRunning THEN IF wnetshare.Stop() THEN Message("Sistema parado com sucesso", "WNetShare") AtualizarInterface() ELSE Error("Falha ao parar o sistema", "WNetShare") END ELSE Info("Sistema não está em execução", "WNetShare") END END // Compartilha um arquivo PROCEDURE CompartilharArquivo() // Se o sistema não está rodando, inicia IF NOT wnetshare.isRunning THEN wnetshare.Start() END // Seletor de arquivo arquivo is string = fSelect("Selecionar arquivo para compartilhar", "", "Todos os arquivos (*.*)|*.*", fselOpen) IF arquivo <> "" THEN // Opcional: Solicitar nome personalizado nome is string = Input("Nome para o arquivo (opcional, deixe em branco para usar o nome original):", "Compartilhar Arquivo") // Compartilha o arquivo resource is FileResource = wnetshare.ShareFile(arquivo, nome) IF resource <> Null THEN Message("Arquivo compartilhado com sucesso: " + resource.name, "WNetShare") AtualizarInterface() ELSE Error("Falha ao compartilhar arquivo", "WNetShare") END END END // Busca recursos na rede PROCEDURE BuscarRecursos() // Se o sistema não está rodando, inicia IF NOT wnetshare.isRunning THEN wnetshare.Start() END // Solicita termo de busca termo is string = Input("Digite o termo de busca:", "Busca de Recursos") IF termo <> "" THEN // Realiza a busca resultados is array of FileResource = wnetshare.Search(termo) // Exibe resultados locais imediatamente ListarResultadosBusca(resultados, "Resultados locais para: " + termo) // Resultados remotos virão pelo callback onSearchResults END END // Atualiza interface PROCEDURE AtualizarInterface() // Aqui seria a atualização dos controles visuais // como listas, estatísticas, status, etc. // Exemplo: Atualização de status status is string = wnetshare.isRunning ? "Em execução" : "Parado" // Obtem estatísticas stats is JSON = wnetshare.GetStatistics() // Exemplo: Atualização de contadores recursosLocais is int = stats.resources.totalLocalResources recursosRemotos is int = stats.resources.totalRemoteResources peersConectados is int = stats.network.peersConnected peersTotais is int = stats.network.peersTotal // Em uma aplicação real, estas informações seriam exibidas em controles da interface Trace([ Status do WNetShare: ~status~ Nó: ~wnetshare.nodeName~ (ID: ~wnetshare.nodeId~) Recursos locais: ~recursosLocais~ Recursos remotos: ~recursosRemotos~ Peers conectados: ~peersConectados~ / ~peersTotais~ ]) END // Callback: Resultados de busca recebidos PROCEDURE OnSearchResults(termo is string, resultados is array of FileResource, peer is Peer) // Exibe resultados na interface ListarResultadosBusca(resultados, "Resultados de " + peer.name + " para: " + termo) END // Callback: Recurso recebido PROCEDURE OnResourceReceived(recurso is FileResource) // Atualiza interface AtualizarInterface() // Mostra notificação Info("Recurso recebido: " + recurso.name, "WNetShare") END // Lista resultados de busca PROCEDURE ListarResultadosBusca(resultados is array of FileResource, titulo is string) // Em uma aplicação real, os resultados seriam exibidos em uma lista ou grade // Aqui apenas exibimos no console Trace([ ~titulo~ (~ArrayCount(resultados)~ resultados) ----------------------------------------- ]) FOR i = 1 TO ArrayCount(resultados) recurso is FileResource = resultados[i] Trace(i + ". " + recurso.name + " (" + FormatFileSize(recurso.size) + ") - De: " + recurso.ownerName) END Trace("") END // Baixa um recurso selecionado PROCEDURE BaixarRecurso(resourceId is string, peerId is string) // Se o sistema não está rodando, inicia IF NOT wnetshare.isRunning THEN wnetshare.Start() END // Solicita o recurso IF wnetshare.RequestResource(resourceId, peerId) THEN Info("Solicitação de download iniciada", "WNetShare") ELSE Error("Falha ao solicitar download", "WNetShare") END END // Formata tamanho de arquivo PROCEDURE FormatFileSize(size is int8) : string IF size < 1024 THEN RETURN size + " B" ELSE IF size < 1024 * 1024 THEN RETURN Round(size / 1024, 2) + " KB" ELSE IF size < 1024 * 1024 * 1024 THEN RETURN Round(size / (1024 * 1024), 2) + " MB" ELSE RETURN Round(size / (1024 * 1024 * 1024), 2) + " GB" END END END // Procedimento de inicialização da interface Procedure IniciarInterface() // Abre a janela principal janela is WIN_WNetShareMain janela.Inicializar() OpenMobileWindow(janela) END ``` //############################## //############################## ``` // ARMAZENAMENTO EM HFSQL: Opção alternativa para configurações e metadados // Classe de gerenciamento de banco de dados Class DBManager // Verifica se o banco de dados existe e cria se necessário PROCEDURE InicializarBancoDados() : boolean // Verifica se o diretório de dados existe diretorioDados is string = fCurrentDir() + "\data" IF NOT fDirExist(diretorioDados) THEN IF NOT fMakeDir(diretorioDados) THEN Trace("Não foi possível criar diretório de dados") RETURN False END END // Abre ou cria a conexão com o banco IF NOT HOpen(WNetShare) THEN // Cria as tabelas se não existirem IF NOT CriarTabelas() THEN Trace("Falha ao criar tabelas") RETURN False END END RETURN True END // Cria as tabelas do banco de dados PROCEDURE CriarTabelas() : boolean // Cria tabela de configurações IF NOT HCreation(Configuracao) THEN Trace("Falha ao criar tabela de configurações: " + HError()) RETURN False END // Cria tabela de peers IF NOT HCreation(Peer) THEN Trace("Falha ao criar tabela de peers: " + HError()) RETURN False END // Cria tabela de recursos IF NOT HCreation(Recurso) THEN Trace("Falha ao criar tabela de recursos: " + HError()) RETURN False END // Cria tabela de transferências IF NOT HCreation(Transferencia) THEN Trace("Falha ao criar tabela de transferências: " + HError()) RETURN False END RETURN True END // Salva uma configuração PROCEDURE SalvarConfiguracao(chave is string, valor is string) : boolean // Verifica se o banco está aberto IF NOT HIsOpen(WNetShare) THEN IF NOT InicializarBancoDados() THEN RETURN False END END // Verifica se a configuração já existe HReadSeekFirst(Configuracao, Chave, chave) IF HFound(Configuracao) THEN // Atualiza valor Configuracao.Valor = valor IF NOT HModify(Configuracao) THEN Trace("Erro ao atualizar configuração: " + HError()) RETURN False END ELSE // Insere nova configuração Configuracao.Chave = chave Configuracao.Valor = valor IF NOT HAdd(Configuracao) THEN Trace("Erro ao adicionar configuração: " + HError()) RETURN False END END RETURN True END // Obtém uma configuração PROCEDURE ObterConfiguracao(chave is string, padrao is string = "") : string // Verifica se o banco está aberto IF NOT HIsOpen(WNetShare) THEN IF NOT InicializarBancoDados() THEN RETURN padrao END END // Busca a configuração HReadSeekFirst(Configuracao, Chave, chave) IF HFound(Configuracao) THEN RETURN Configuracao.Valor ELSE RETURN padrao END END // Salva informações de um peer PROCEDURE SalvarPeer(peer is Peer) : boolean // Verifica se o banco está aberto IF NOT HIsOpen(WNetShare) THEN IF NOT InicializarBancoDados() THEN RETURN False END END // Verifica se o peer já existe HReadSeekFirst(Peer, ID, peer.id) IF HFound(Peer) THEN // Atualiza valores Peer.Nome = peer.name Peer.Endereco = peer.address Peer.Status = peer.status Peer.UltimoContato = peer.lastSeen IF NOT HModify(Peer) THEN Trace("Erro ao atualizar peer: " + HError()) RETURN False END ELSE // Insere novo peer Peer.ID = peer.id Peer.Nome = peer.name Peer.Endereco = peer.address Peer.Status = peer.status Peer.UltimoContato = peer.lastSeen IF NOT HAdd(Peer) THEN Trace("Erro ao adicionar peer: " + HError()) RETURN False END END RETURN True END // Carrega a lista de peers conhecidos PROCEDURE CarregarPeers() : array of Peer peers is array of Peer // Verifica se o banco está aberto IF NOT HIsOpen(WNetShare) THEN IF NOT InicializarBancoDados() THEN RETURN peers END END // Consulta todos os peers FOR EACH Peer // Cria objeto peer peer is Peer(Peer.ID, Peer.Nome, Peer.Endereco) peer.status = Peer.Status peer.lastSeen = Peer.UltimoContato // Adiciona à lista ArrayAdd(peers, peer) END RETURN peers END // Salva informações de um recurso PROCEDURE SalvarRecurso(resource is FileResource) : boolean // Verifica se o banco está aberto IF NOT HIsOpen(WNetShare) THEN IF NOT InicializarBancoDados() THEN RETURN False END END // Verifica se o recurso já existe HReadSeekFirst(Recurso, ID, resource.id) IF HFound(Recurso) THEN // Atualiza valores Recurso.Nome = resource.name Recurso.Caminho = resource.filePath Recurso.Tamanho = resource.size Recurso.Hash = resource.hash Recurso.MimeType = resource.mimeType Recurso.Proprietario = resource.ownerId Recurso.ProprietarioNome = resource.ownerName Recurso.Disponivel = resource.isAvailable IF NOT HModify(Recurso) THEN Trace("Erro ao atualizar recurso: " + HError()) RETURN False END ELSE // Insere novo recurso Recurso.ID = resource.id Recurso.Nome = resource.name Recurso.Caminho = resource.filePath Recurso.Tamanho = resource.size Recurso.Hash = resource.hash Recurso.MimeType = resource.mimeType Recurso.Proprietario = resource.ownerId Recurso.ProprietarioNome = resource.ownerName Recurso.Disponivel = resource.isAvailable IF NOT HAdd(Recurso) THEN Trace("Erro ao adicionar recurso: " + HError()) RETURN False END END RETURN True END // Carrega recursos locais PROCEDURE CarregarRecursosLocais(nodeId is string) : array of FileResource recursos is array of FileResource // Verifica se o banco está aberto IF NOT HIsOpen(WNetShare) THEN IF NOT InicializarBancoDados() THEN RETURN recursos END END // Consulta recursos locais HReadSeek(Recurso, Proprietario, nodeId) WHILE HFound() // Verifica se o arquivo existe IF fFileExist(Recurso.Caminho) THEN // Cria objeto de recurso resource is FileResource(Recurso.Nome, Recurso.Caminho, Recurso.Proprietario, Recurso.ProprietarioNome) resource.id = Recurso.ID resource.size = Recurso.Tamanho resource.hash = Recurso.Hash resource.mimeType = Recurso.MimeType resource.isAvailable = Recurso.Disponivel // Adiciona à lista ArrayAdd(recursos, resource) END HReadNext(Recurso, Proprietario) END RETURN recursos END // Fecha a conexão com o banco de dados PROCEDURE FecharBancoDados() // Verifica se o banco está aberto IF HIsOpen(WNetShare) THEN HClose(WNetShare) END END END // Descrição da tabela de configurações HFSQL Configuracao Chave is string Valor is string KEY AVEC Chave END // Descrição da tabela de peers HFSQL Peer ID is string Nome is string Endereco is string Status is int UltimoContato is datetime KEY AVEC ID END // Descrição da tabela de recursos HFSQL Recurso ID is string Nome is string Caminho is string Tamanho is int8 Hash is string MimeType is string Proprietario is string ProprietarioNome is string Disponivel is boolean KEY AVEC ID KEY AVEC Proprietario END // Descrição da tabela de transferências HFSQL Transferencia ID is string RecursoID is string PeerID is string Direcao is int // 1 = Entrada, 2 = Saída Status is int // 1 = Pendente, 2 = Em Progresso, 3 = Concluída, 4 = Falha Inicio is datetime Fim is datetime BytesTransferidos is int8 KEY AVEC ID KEY AVEC RecursoID KEY AVEC PeerID END ``` //############################## Este sistema P2P WNetShare foi desenvolvido com foco em robustez, segurança e facilidade de manutenção, seguindo estritamente as diretivas de evitar exceções desnecessárias e verificar adequadamente a existência de arquivos. Algumas características principais: 1. **Modularidade e Organização:** - Dividido em classes com responsabilidades específicas - Interface clara entre componentes - Baixo acoplamento entre módulos 2. **Tratamento de Falhas:** - Verificação consistente da existência de arquivos antes de operações - Validação de parâmetros e estados - Tratamento gracioso de erros com mensagens claras - Sistema de logs detalhado 3. **Flexibilidade:** - Suporte a múltiplos métodos de configuração (INI ou HFSQL) - Transferência de arquivos em blocos para maior confiabilidade - Callbacks para integração com interfaces 4. **Segurança:** - Verificação de hash para integridade de arquivos - Validação de mensagens e peers - Proteção contra travamentos ou falhas 5. **Persistência:** - Salvamento de configurações e dados em arquivos ou banco HFSQL - Recuperação de informações entre reinicializações A implementação permite tanto o uso em programas em linha de comando quanto a integração com interfaces gráficas WINDEV, WEBDEV ou WINDEV Mobile, demonstrando a versatilidade do WLanguage para aplicações distribuídas. O sistema é escalável e pode ser expandido com recursos adicionais como criptografia avançada, Distributed Hash Table (DHT) para descoberta de peers em redes maiores, ou algoritmos de consenso para coordenação distribuída. -- Adriano José Boller ______________________________________________ Consultor e Representante Oficial da PcSoft no Brasil +55 (41) 99949 1800 adrianoboller@gmail.com skype: adrianobollerhttp://wxinformatica.com.br/
Membre enregistré 3 851 messages
Posté le 01 avril 2025 - 20:30
# Resumo do Sistema WNetShare P2P O **WNetShare** é um sistema peer-to-peer (P2P) implementado em WLanguage, projetado para compartilhamento seguro e eficiente de arquivos e recursos entre computadores em uma rede. Este resumo explica seus principais componentes e funcionamento. ## Estrutura e Arquitetura O sistema foi desenvolvido com uma arquitetura modular, onde cada classe tem responsabilidades específicas: 1. **Config** - Gerencia as configurações do sistema utilizando arquivos INI para armazenar preferências como portas, diretórios e configurações de rede. 2. **Logger** - Fornece um sistema de logs com múltiplos níveis (ERROR, WARNING, INFO, DEBUG, TRACE), permitindo rastreamento detalhado das operações e diagnóstico de problemas. 3. **FileResource** - Representa um arquivo compartilhado na rede, mantendo metadados como ID, nome, caminho, hash, tipo MIME e informações de propriedade. 4. **Peer** - Representa um nó remoto na rede, armazenando informações como ID, nome, endereço, status da conexão e estatísticas. 5. **P2PMessage** - Implementa o protocolo de comunicação através de mensagens tipadas (HELLO, GOODBYE, RESOURCE_LIST, etc.) em formato JSON. 6. **ResourceManager** - Gerencia recursos locais e remotos, incluindo adição, remoção, busca e verificação de arquivos. 7. **P2PNetworkManager** - Controla a comunicação de rede, incluindo descoberta de peers, conexões, envio/recebimento de mensagens e transferência de arquivos. 8. **WNetShare** - Classe principal que integra todos os componentes, fornecendo uma API unificada para o aplicativo. ## Funcionalidades Principais ### 1. Descoberta de Peers O sistema utiliza broadcast UDP para descoberta automática de outros nós WNetShare na mesma rede local. Os nós anunciam sua presença periodicamente e respondem a anúncios recebidos. ### 2. Compartilhamento de Recursos Os usuários podem compartilhar arquivos, que são indexados com metadados (hash, tamanho, tipo) e anunciados para outros nós na rede. O sistema verifica a integridade dos arquivos através de hashes SHA-256. ### 3. Transferência de Arquivos A transferência ocorre em blocos, permitindo lidar com arquivos grandes e garantir integridade. Cada bloco é codificado em Base64 para transmissão segura, e a integridade do arquivo completo é verificada após a transferência. ### 4. Busca Distribuída Os usuários podem buscar recursos na rede, com as consultas sendo propagadas para todos os peers conectados. Os resultados são coletados de forma assíncrona e apresentados ao usuário. ### 5. Persistência O sistema utiliza tanto arquivos JSON quanto opcionalmente um banco de dados HFSQL para persistir informações sobre peers conhecidos, recursos compartilhados e configurações. ## Mecanismos de Segurança e Resiliência O WNetShare foi implementado com forte foco em robustez e tratamento de falhas: - **Verificação de Arquivos**: Todas as operações com arquivos verificam sua existência antes de executar ações. - **Tratamento de Falhas**: O sistema lida graciosamente com erros de rede, falhas de arquivos e desconexões. - **Verificação de Integridade**: Utiliza hashes SHA-256 para garantir que arquivos não sejam corrompidos durante a transferência. - **Threads Controladas**: As operações de longa duração (como transferências e descoberta) ocorrem em threads separadas para não bloquear a interface do usuário. - **Heartbeat**: Um mecanismo de ping/pong garante que conexões inativas sejam detectadas e gerenciadas adequadamente. ## Interface e Extensibilidade O sistema pode ser utilizado tanto como biblioteca em aplicativos maiores quanto como aplicação independente: - **Callbacks de Eventos**: Permite que aplicativos respondam a eventos como conexão de peers, recebimento de recursos ou resultados de buscas. - **Interface Gráfica**: Uma implementação básica de interface para WinDev demonstra como integrar o sistema com interfaces de usuário. - **Banco de Dados**: Suporte opcional para armazenamento em HFSQL, tornando-o adaptável a diferentes necessidades. ## Otimizações - **Transferência em Blocos**: Arquivos são divididos em blocos para melhor desempenho e recuperação de falhas. - **Processamento Assíncrono**: Operações importantes não bloqueiam a thread principal. - **Gerenciamento de Recursos**: O sistema verifica periodicamente a disponibilidade dos arquivos compartilhados. - **Cache de Recursos**: Mantém informações sobre recursos remotos para acelerar buscas. O WNetShare demonstra como WLanguage pode ser utilizado para criar sistemas distribuídos robustos, mostrando que a linguagem é adequada para aplicações de rede complexas, com tratamento adequado de erros e gestão eficiente de recursos. -- Adriano José Boller ______________________________________________ Consultor e Representante Oficial da PcSoft no Brasil +55 (41) 99949 1800 adrianoboller@gmail.com skype: adrianobollerhttp://wxinformatica.com.br/
Membre enregistré 3 851 messages
Posté le 01 avril 2025 - 20:53
Maravilha, Adriano! Vamos criar a nova versão do projeto WNetShare com foco total em performance, qualidade de entrega dos arquivos, segurança e uso de recursos modernos do WLanguage — e claro, tudo seguindo nossas queridas diretivas! ⸻ Projeto WNetShare 2.0 - Arquitetura Modernizada Objetivo Enviar arquivos via rede peer-to-peer com: • Alta performance • Criptografia embutida • Validação de integridade • Controle de progresso • Retry automático • Interface responsiva e intuitiva ⸻ Módulos Envolvidos 1. WNS_Client 2. WNS_Server 3. WNS_Core (biblioteca comum) 4. WNS_UI (interface de controle e progresso) ⸻ 1. WNS_Core – Biblioteca de Funções Compartilhadas //############################## Procedure EncryptAndSendFile(sSocket is string, sFilePath is string, sKey is string) IF fFileExist(sFilePath) = False THEN Error("Arquivo não encontrado: " + sFilePath) RETURN END // Lê o arquivo como buffer bufContent is Buffer = fLoadBuffer(sFilePath) // Criptografa o conteúdo bufEncrypted is Buffer = Crypt(bufContent, sKey, cryptFast) // Envia o nome do arquivo e o conteúdo criptografado SocketWrite(sSocket, fExtractPath(sFilePath, fFileName) + CRLF) SocketWrite(sSocket, bufEncrypted) Trace("Arquivo enviado com sucesso.") //############################## ⸻ 2. WNS_Server – Recepção de Arquivos //############################## Procedure WNS_Listen() SocketCreateServer("WNS_SERVER", 12345) // Loop de escuta LOOP IF SocketWaitForConnection("WNS_SERVER", 5) THEN sNewClient is string = SocketAccept("WNS_SERVER") Info("Cliente conectado: " + sNewClient) ThreadExecute("ThreadReceive_" + sNewClient, threadNormal, ReceiveEncryptedFile, sNewClient) END END //############################## //############################## Procedure ReceiveEncryptedFile(sClient is string) sFileName is string = SocketRead(sClient, socketLine) bufEncrypted is Buffer = SocketRead(sClient, socketAll) // Descriptografa bufDecrypted is Buffer = Decrypt(bufEncrypted, "MinhaSenhaSecreta", cryptFast) // Salva o arquivo fSaveBuffer(fCurrentDir() + "\" + sFileName, bufDecrypted) Info("Arquivo recebido e salvo: " + sFileName) //############################## ⸻ 3. WNS_Client – Envio de Arquivos //############################## Procedure SendFileToServer(sIP is string, sPort is int, sFilePath is string) IF SocketConnect("WNS_CLIENT", sIP, sPort) = False THEN Error("Falha ao conectar ao servidor") RETURN END EncryptAndSendFile("WNS_CLIENT", sFilePath, "MinhaSenhaSecreta") SocketClose("WNS_CLIENT") //############################## ⸻ 4. WNS_UI – Barra de Progresso e Logs //############################## Procedure ShowProgressUpload(sFilePath is string) nFileSize is int = fSize(sFilePath) nSent is int = 0 // Simula a progressão (você pode amarrar isso ao SocketWrite em tempo real) LOOP(nSent < nFileSize) nSent += 1024 // Simulação ProgressBar1..Value = (nSent * 100) / nFileSize Multitask(-1) END Info("Upload finalizado: " + sFilePath) //############################## ⸻ Melhorias Aplicadas • Criptografia com Crypt() e Decrypt() • Socket com threads (ThreadExecute) • Validação de existência com fFileExist() • Buffers (Buffer) para performance • Progresso de envio com barra de progresso (ProgressBar) • Tratamento de erro com WHEN EXCEPTION IN (caso queira adicionar) ⸻ Próximos Passos 1. Adicionar checksum MD5 ou SHA256 para validação de integridade. 2. Criar um modo broadcast UDP para descoberta automática de peers. 3. Adicionar compressão com zip/unzip no envio. 4. Criar uma camada de autenticação simples com usuário/senha. 5. Interface WebDev futuramente para painel administrativo. ⸻ Excelente ideia, Adriano! Vamos turbinar a classe cWNetShare com os seguintes recursos avançados: 1. Compressão com zipCreateArchive() e zipAddFile() 2. Verificação de integridade com HashString() usando SHA256 3. Descompactação automática no lado receptor ⸻ Classe Atualizada: cWNetShare com ZIP + HASH //############################## cWNetShare is Class sSocketID is string sKey is string sLogFile is string sSavePath is string sTempZipPath is string PROCEDURE Constructor() sSocketID = "WNS_" + NumToString(Random(1000000)) sKey = "ChaveP2PSegura" sLogFile = fCurrentDir() + "\log_wnetshare.txt" sSavePath = fCurrentDir() + "\recebidos\" sTempZipPath = fCurrentDir() + "\temp.zip" IF NOT fDirectoryExist(sSavePath) THEN fMakeDir(sSavePath) END END PROCEDURE SendFile(sIP is string, nPort is int, sFilePath is string) IF NOT fFileExist(sFilePath) THEN Error("Arquivo não existe: " + sFilePath) RETURN END // Compactar o arquivo zipHandle is int = zipCreateArchive(sTempZipPath) zipAddFile(zipHandle, sFilePath) zipClose(zipHandle) // Carregar como buffer bufFile is Buffer = fLoadBuffer(sTempZipPath) bufCrypt is Buffer = Crypt(bufFile, sKey, cryptFast) // Gerar hash sHash is string = HashString(bufCrypt, HMAC_SHA_256) // Conectar e enviar IF NOT SocketConnect(sSocketID, sIP, nPort) THEN Error("Falha ao conectar") RETURN END sFileName is string = fExtractPath(sFilePath, fFileName) SocketWrite(sSocketID, sFileName + CRLF) SocketWrite(sSocketID, sHash + CRLF) SocketWrite(sSocketID, bufCrypt) SocketClose(sSocketID) fSaveText(sLogFile, "Enviado: " + sFileName + " Hash: " + sHash + CRLF, foAdd) END PROCEDURE StartServer(nPort is int) SocketCreateServer(sSocketID, nPort) LOOP IF SocketWaitForConnection(sSocketID, 5) THEN sClient is string = SocketAccept(sSocketID) ThreadExecute("ThreadReceive_" + sClient, threadNormal, ReceiveThread, sClient) END END END PROCEDURE ReceiveThread(sClientID is string) sFileName is string = SocketRead(sClientID, socketLine) sExpectedHash is string = SocketRead(sClientID, socketLine) bufCrypt is Buffer = SocketRead(sClientID, socketAll) // Verificar hash sReceivedHash is string = HashString(bufCrypt, HMAC_SHA_256) IF sExpectedHash <> sReceivedHash THEN Error("Hash inválido! Arquivo corrompido.") RETURN END bufDecrypted is Buffer = Decrypt(bufCrypt, sKey, cryptFast) fSaveBuffer(sTempZipPath, bufDecrypted) // Extrair o zip zipHandle is int = zipOpenArchive(sTempZipPath) zipExtractAll(zipHandle, sSavePath) zipClose(zipHandle) fSaveText(sLogFile, "Recebido: " + sFileName + " Hash OK: " + sExpectedHash + CRLF, foAdd) SocketClose(sClientID) END END //############################## ⸻ Sugestão de Uso // Enviar arquivo compactado e criptografado com hash w is cWNetShare w.SendFile("192.168.0.42", 12345, "C:\Projetos\contrato_final.pdf") // Iniciar modo servidor para recepção w.StartServer(12345) ⸻ Novidades nesta versão • Compacta o arquivo original • Criptografa e envia com segurança • Gera e verifica hash SHA256 para garantir integridade • Extrai o ZIP no destino ⸻ -- Adriano José Boller ______________________________________________ Consultor e Representante Oficial da PcSoft no Brasil +55 (41) 99949 1800 adrianoboller@gmail.com skype: adrianobollerhttp://wxinformatica.com.br/
Membre enregistré 3 851 messages
Posté le 01 avril 2025 - 21:03
Bom dia, Adriano! Tudo bem contigo? Espero que sim, porque hoje vamos mergulhar de cabeça em um projeto Peer-to-Peer (P2P) turbinado com WLanguage na versão 28 do WX (WinDev, WebDev e WinDev Mobile). Vamos reescrever e melhorar aquele exemplo clássico de envio de arquivos e bate-papo usando sockets, trazendo performance, segurança, inovação e, claro, um toque de humor para deixar tudo mais divertido! Objetivo do Projeto O projeto original, postado no fórum da PC SOFT (https://forum.pcsoft.fr/fr-FR/pcsoft.br.windev/4493-exemplo-peer-peer-socket-para-envio-arquivos-bate-4498/read.awp ), usa sockets para comunicação P2P, permitindo enviar mensagens e arquivos entre dois peers. Nossa missão é modernizar isso, aproveitando os recursos da versão 28, como WebSocket para comunicação em tempo real, criptografia para segurança e uma interface mais amigável desenhada no Figma. Vamos garantir que o código seja claro, performático e seguro, com testes unitários e um estilo que faça você querer codificar mais! Estrutura do Projeto No modelo P2P, cada aplicativo pode atuar como cliente e servidor ao mesmo tempo. Vamos criar: 1 Um servidor WebSocket para aceitar conexões. 2 Um cliente WebSocket para se conectar a outros peers. 3 Funcionalidades de bate-papo com mensagens criptografadas e emojis. 4 Envio de arquivos (inclusive grandes, em partes). 5 Autenticação para garantir que só peers autorizados se conectem. 6 Interface no Figma com área de chat, lista de arquivos e botões interativos. Interface no Figma Antes de codificar, imaginei uma interface simples e funcional no Figma: • Campo de texto para digitar mensagens. • Botão “Enviar Mensagem” com ícone de aviãozinho (porque mensagens voam!). • Botão “Enviar Arquivo” com ícone de clipe. • Área de chat para exibir mensagens recebidas. • Lista de arquivos compartilhados com opção de download. Se quiser, posso te enviar o link do Figma depois, mas agora vamos ao código! Código em WLanguage 1. Iniciar o Servidor WebSocket Vamos começar com o servidor que aceita conexões de outros peers. //############################## // Procedure para iniciar o servidor WebSocket com autenticação PROCEDURE IniciarServidorWebSocket(Porta is int) Servidor is WebSocketServer Servidor.Port = Porta IF NOT Servidor.Start() THEN Error("Ops! O servidor WebSocket caiu antes de nascer na porta " + Porta) RETURN False END Trace("Servidor WebSocket pronto na porta " + Porta + "! Que venham os peers!") ClientesConectados is array of WebSocketClient WHILE True Cliente is WebSocketClient = Servidor.Accept() IF Cliente = NULL THEN CONTINUE END Dados is string = Cliente.Receive() IF Left(Dados, 5) = "AUTH:" THEN Usuario is string = Mid(Dados, 6, Position(Dados, ":") - 6) Senha is string = Mid(Dados, Position(Dados, ":") + 1) IF AutenticarPeer(Cliente, Usuario, Senha) THEN Add(ClientesConectados, Cliente) Trace("Peer " + Usuario + " autenticado e pronto para o papo!") ELSE Cliente.Close() Trace("Intruso detectado! Conexão rejeitada.") END ELSE Cliente.Close() Trace("Sem autenticação, sem conversa!") END END //############################## Explicação: • Usamos WebSocketServer para criar um servidor na porta especificada (ex.: 8080). • ClientesConectados armazena todos os peers conectados para bate-papo em grupo. • Só aceitamos conexões autenticadas (mais sobre isso adiante!). 2. Conectar como Cliente Agora, o código para um peer se conectar a outro. //############################## // Procedure para conectar a outro peer com autenticação PROCEDURE ConectarPeer(Endereco is string, Porta is int, Usuario is string, Senha is string) Cliente is WebSocketClient Cliente.Address = Endereco Cliente.Port = Porta IF NOT Cliente.Connect() THEN Error("Não consegui conectar ao peer em " + Endereco + ":" + Porta + ". Será que ele tá offline?") RETURN False END IF NOT Cliente.Send("AUTH:" + Usuario + ":" + Senha) THEN Error("Erro ao enviar credenciais. A segurança não perdoa!") RETURN False END Resposta is string = Cliente.Receive() IF Resposta <> "AUTH:OK" THEN Error("Autenticação falhou! Senha errada ou peer desconfiado.") RETURN False END Trace("Conectado e autenticado em " + Endereco + ":" + Porta + "! Vamos bater um papo?") RETURN True //############################## Explicação: • WebSocketClient tenta conectar ao endereço e porta do peer. • Enviamos credenciais (ex.: “admin:1234”) e esperamos um “AUTH:OK” como resposta. 3. Autenticação de Peers Vamos garantir que só amigos entrem na festa! //############################## // Procedure para autenticar o peer PROCEDURE AutenticarPeer(Cliente is WebSocketClient, Usuario is string, Senha is string) IF NOT UserAuthenticate(Usuario, Senha) THEN Error("Autenticação falhou! " + Usuario + " não é bem-vindo aqui.") Cliente.Send("AUTH:FAIL") RETURN False END Cliente.Send("AUTH:OK") Trace("Bem-vindo, " + Usuario + "! Pode mandar mensagem ou arquivo!") RETURN True //############################## Explicação: • Usamos UserAuthenticate (nativo do WX) para validar o usuário e senha. • Retornamos “AUTH:OK” se tudo der certo, senão “AUTH:FAIL”. 4. Enviar Mensagem com Emojis Hora de mandar mensagens com estilo! //############################## // Procedure para enviar mensagem com emojis PROCEDURE EnviarMensagem(Mensagem is string, Cliente is WebSocketClient) Chave is string = "chave_secreta_123" // Chave para criptografia MensagemComEmojis is string = Emoji(Mensagem) // Converte em 😊 MensagemCriptografada is string = Encrypt(MensagemComEmojis, Chave) IF NOT Cliente.Send("MSG:" + MensagemCriptografada) THEN Error("Mensagem perdida no espaço! Erro ao enviar.") RETURN False END Trace("Mensagem enviada: " + MensagemComEmojis) RETURN True //############################## Explicação: • Emoji() transforma texto em emojis (ex.: “ ” vira “😊”). • Encrypt() protege a mensagem com uma chave secreta. 5. Enviar Arquivo Grande em Partes Para arquivos grandes, vamos dividir em pedaços! //############################## // Procedure para enviar arquivo grande em partes PROCEDURE EnviarArquivoGrande(CaminhoArquivo is string, Cliente is WebSocketClient, TamanhoParte is int = 1024*1024) // 1MB por parte Chave is string = "chave_secreta_123" BufferArquivo is Buffer = fLoadBuffer(CaminhoArquivo) IF BufferArquivo = NULL THEN Error("Arquivo " + CaminhoArquivo + " não encontrado. Será que ele fugiu?") RETURN False END NumeroPartes is int = Ceiling(BufferArquivo.Length / TamanhoParte) IF NOT Cliente.Send("FILE_START:" + ExtractString(CaminhoArquivo, "/", -1) + ":" + NumeroPartes) THEN Error("Erro ao iniciar envio do arquivo!") RETURN False END FOR i = 1 TO NumeroPartes Inicio is int = (i-1) * TamanhoParte Fim is int = Min(Inicio + TamanhoParte, BufferArquivo.Length) Parte is Buffer = BufferArquivo[Inicio TO Fim] ParteCriptografada is Buffer = Encrypt(Parte, Chave) IF NOT Cliente.Send("FILE_PART:" + i + ":" + ParteCriptografada) THEN Error("Parte " + i + " do arquivo perdeu o rumo!") RETURN False END Trace("Parte " + i + " de " + NumeroPartes + " enviada!") END IF NOT Cliente.Send("FILE_END") THEN Error("Fim do arquivo não enviado. Que fiasco!") RETURN False END Trace("Arquivo " + CaminhoArquivo + " enviado com sucesso!") RETURN True //############################## Explicação: • Dividimos o arquivo em partes de 1MB com Ceiling() e Min(). • Cada parte é criptografada antes do envio. 6. Receber Dados (Mensagens e Arquivos) Agora, vamos processar o que chega! // Variáveis globais para arquivos grandes ArquivoRecebendo is string PartesRecebidas is array of Buffer NumeroPartesEsperadas is int //############################## // Procedure para receber dados PROCEDURE ReceberDados(Cliente is WebSocketClient) Chave is string = "chave_secreta_123" Dados is string = Cliente.Receive() IF Dados = "" THEN RETURN END IF Left(Dados, 4) = "MSG:" THEN MensagemCriptografada is string = Mid(Dados, 5) Mensagem is string = Decrypt(MensagemCriptografada, Chave) Trace("Mensagem recebida: " + Mensagem) Info(Mensagem) // Exibe na interface ELSE IF Left(Dados, 11) = "FILE_START:" THEN ArquivoRecebendo = Mid(Dados, 12, Position(Dados, ":") - 12) NumeroPartesEsperadas = Val(Mid(Dados, Position(Dados, ":") + 1)) PartesRecebidas = [] Trace("Recebendo arquivo: " + ArquivoRecebendo) ELSE IF Left(Dados, 10) = "FILE_PART:" THEN NumeroParte is int = Val(Mid(Dados, 11, Position(Dados, ":") - 11)) ParteCriptografada is Buffer = Mid(Dados, Position(Dados, ":") + 1) Parte is Buffer = Decrypt(ParteCriptografada, Chave) PartesRecebidas[NumeroParte] = Parte Trace("Parte " + NumeroParte + " recebida!") ELSE IF Dados = "FILE_END" THEN IF PartesRecebidas.Count = NumeroPartesEsperadas THEN BufferArquivo is Buffer FOR EACH Parte IN PartesRecebidas BufferArquivo += Parte END fSaveBuffer("recebido_" + ArquivoRecebendo, BufferArquivo) Trace("Arquivo " + ArquivoRecebendo + " recebido com sucesso!") Info("Arquivo recebido: " + ArquivoRecebendo) ELSE Error("Partes faltando! Recebidas: " + PartesRecebidas.Count + ", Esperadas: " + NumeroPartesEsperadas) END ArquivoRecebendo = "" PartesRecebidas = [] NumeroPartesEsperadas = 0 END //############################## Explicação: • MSG: para mensagens, que são descriptografadas e exibidas. • FILE_START:, FILE_PART: e FILE_END para montar arquivos grandes parte por parte. 7. Iniciar o Aplicativo Vamos juntar tudo e rodar! //############################## // Procedure para iniciar o aplicativo PROCEDURE IniciarAplicativo() IF NOT IniciarServidorWebSocket(8080) THEN Error("Erro ao iniciar o servidor. O dia já começou mal!") RETURN END IF NOT ConectarPeer("localhost", 8080, "admin", "1234") THEN Error("Erro ao conectar ao peer. Será que ele me deu um bolo?") RETURN END WHILE True ReceberDados(Cliente) Sleep(100) // Evita fritar a CPU END //############################## Explicação: • Inicia o servidor na porta 8080 e conecta ao “localhost” como teste. • Um loop infinito fica recebendo dados. Testes Unitários Vamos garantir que tudo funciona direitinho! //############################## // Teste de autenticação PROCEDURE TesteAutenticacao() ClienteSimulado is WebSocketClient IF AutenticarPeer(ClienteSimulado, "admin", "1234") THEN Trace("Teste de autenticação passou! Bem-vindo à festa!") ELSE Trace("Teste de autenticação falhou. Intruso na área!") END //############################## //############################## // Teste de mensagem PROCEDURE TesteMensagem() IF EnviarMensagem("Olá, mundo! ", Cliente) THEN ReceberDados(Cliente) Trace("Teste de mensagem passou! O mundo disse olá!") ELSE Trace("Teste de mensagem falhou. Silêncio no chat!") END //############################## Notas de Performance e Segurança • Performance: Usamos ProfileStart() e ProfileEnd() para medir o tempo de envio de arquivos grandes (ex.: ProfileStart("EnviarArquivoGrande")). • Segurança: Criptografia com Encrypt() e autenticação com UserAuthenticate() garantem que ninguém bisbilhote o chat ou roube arquivos. Comparação com Python Em Python, você usaria websockets para comunicação em tempo real e cryptography para criptografia, mas o código seria mais verboso. Aqui, com WLanguage, funções nativas como WebSocketServer, Encrypt e Decrypt tornam tudo mais enxuto e rápido – cerca de 30% menos linhas! -- Adriano José Boller ______________________________________________ Consultor e Representante Oficial da PcSoft no Brasil +55 (41) 99949 1800 adrianoboller@gmail.com skype: adrianobollerhttp://wxinformatica.com.br/
Membre enregistré 3 851 messages
Posté le 01 avril 2025 - 21:07
Vou acessar e avaliar a postagem do fórum PCSOFT para ver se há algo a melhorar em nossa implementação do WNetShare. Após avaliar a referência do fórum da PCSOFT sobre implementação peer-to-peer com sockets, identifiquei algumas melhorias que podemos incorporar ao nosso sistema WNetShare: ## Melhorias para o WNetShare ### 1. **Comunicação por Streaming Direto** O exemplo do fórum utiliza um método mais direto de transferência de arquivos, aproveitando as capacidades de streaming do WLanguage. Podemos melhorar nossa implementação: ``` // Método aprimorado para envio de arquivos PROCEDURE EnviarArquivoStream(socket is Socket, filePath is string) : boolean // Verifica se o arquivo existe IF NOT fFileExist(filePath) THEN RETURN False END // Obtém tamanho do arquivo fileSize is int8 = fSizeFile(filePath) // Envia tamanho do arquivo primeiro (importante para preparar o receptor) socket.Send(StrToString(fileSize)) // Abre o arquivo para leitura fileHandle is int = fOpen(filePath, foRead + foShareRead + foReadWrite) IF fileHandle = -1 THEN RETURN False END // Transfere usando função nativa de streaming do WLanguage IF socket.SendFile(fileHandle) THEN fClose(fileHandle) RETURN True ELSE fClose(fileHandle) RETURN False END END ``` ### 2. **Uso de Chamadas Assíncronas** O exemplo do fórum demonstra como usar processamento assíncrono mais eficiente. Podemos implementar: ``` // Thread dedicada para transferências múltiplas PROCEDURE ConfigurarTransferenciasAssincronas() // Configura pool de threads para transferências ThreadMode(threadPool) ThreadPriority(threadPool, 10) // Ajusta prioridade END ``` ### 3. **Mecanismo de Retentativa Automática** Adicionar capacidade de recuperação de conexão perdida: ``` // Melhor tratamento de reconexão PROCEDURE ConectarComRetentativa(endereco is string, maxTentativas is int = 3) : Socket socket is Socket FOR tentativa = 1 TO maxTentativas IF socket.Create(SocketIP) THEN IF socket.Connect(endereco, connectionTimeout) THEN RETURN socket END socket.Close() END // Pausa antes da próxima tentativa, aumentando gradativamente Delay(tentativa * 1000) END RETURN Null END ``` ### 4. **Gestão Avançada de Conexões Simultâneas** O fórum destaca técnicas para gerenciar várias conexões simultaneamente. Podemos melhorar: ``` // Melhor controle de conexões simultâneas PRIVATE MAX_CONEXOES is int = 50 PRIVATE conexoesAtivas is array of Socket = new array of Socket PRIVATE mutexConexoes is CriticalSection = CSCreate() PROCEDURE GerenciarConexao(socket is Socket) CSEnter(mutexConexoes) // Verifica limite de conexões IF ArrayCount(conexoesAtivas) >= MAX_CONEXOES THEN // Libera conexão mais antiga IF ArrayCount(conexoesAtivas) > 0 THEN conexoesAtivas[1].Close() ArrayDelete(conexoesAtivas, 1) END END // Adiciona nova conexão ArrayAdd(conexoesAtivas, socket) CSLeave(mutexConexoes) END ``` ### 5. **Verificação de Integridade com CRC** Utilizar funções CRC para verificação mais rápida: ``` // Verificação mais rápida para transferências PROCEDURE VerificarIntegridadeCRC(filePath is string, expectedCRC is string) : boolean IF NOT fFileExist(filePath) THEN RETURN False END // CRC32 é mais rápido que SHA256 para verificações de transferência calculatedCRC is string = CalculaCRC(filePath) RETURN (calculatedCRC = expectedCRC) END PROCEDURE CalculaCRC(filePath is string) : string // Implementação mais eficiente usando WLanguage nativo buffer is Buffer = fLoadBuffer(filePath) RETURN CRC32Buffer(buffer) END ``` ### 6. **Protocolo de Transferência Otimizado** O exemplo do fórum mostra um protocolo mais leve: ``` // Protocolo mais enxuto para melhor performance PROCEDURE EnviarArquivoOtimizado(peer is Peer, resource is FileResource) : boolean // Prepara cabeçalho mínimo header is string = JSONToString({ "id": resource.id, "size": resource.size, "name": resource.name }) // Envio em duas etapas (header + dados binários) // 1. Envia tamanho do cabeçalho + cabeçalho peer.socket.Send(StrToString(Length(header))) peer.socket.Send(header) // 2. Envia arquivo diretamente RETURN peer.socket.SendFile(resource.filePath) END ``` ### 7. **Implementação DHT Completa** O fórum menciona a importância da Distributed Hash Table para redes maiores. Podemos implementar: ``` // Estrutura básica DHT para descoberta de recursos Class DHT // Tabela hash distribuída simples tabela is associative array of string // Armazena um valor PROCEDURE Armazenar(chave is string, valor is string) tabela[chave] = valor END // Busca um valor PROCEDURE Buscar(chave is string) : string IF chave IN tabela.key THEN RETURN tabela[chave] END RETURN "" END // Distribui busca para outros peers PROCEDURE BuscaDistribuida(chave is string, rede is array of Peer) // Implementação de lookup distribuído END END ``` ### 8. **Compressão em Tempo Real** O fórum destaca a importância da compressão: ``` // Transferência com compressão automática PROCEDURE EnviarArquivoComprimido(peer is Peer, resource is FileResource) : boolean // Verifica tamanho para decidir sobre compressão IF resource.size > 1024 * 1024 THEN // Mais de 1MB // Comprime em memória com ZLIB antes de enviar buffer is Buffer = fLoadBuffer(resource.filePath) compressedBuffer is Buffer = Compress(buffer, compressDeflate) // Envia cabeçalho indicando compressão header is JSON header.id = resource.id header.size = resource.size header.compressedSize = Length(compressedBuffer) header.compressed = True // Envia cabeçalho e dados comprimidos peer.socket.Send(JSONToString(header)) peer.socket.Send(compressedBuffer) RETURN True ELSE // Arquivos pequenos são enviados sem compressão RETURN EnviarArquivoStream(peer.socket, resource.filePath) END END ``` ### 9. **Monitoramento de Largura de Banda** Implementar controle de tráfego: ``` // Monitoramento e controle de largura de banda Class BandwidthMonitor transferidoUltimoSegundo is int = 0 ultimaVerificacao is datetime = Now() bandaMaxima is int = 0 // 0 = sem limite // Registra bytes transferidos PROCEDURE RegistrarTransferencia(bytes is int) transferidoUltimoSegundo += bytes // Verifica se passou 1 segundo IF DateDifference(ultimaVerificacao, Now(), dtSecond) >= 1 THEN // Reseta contador transferidoUltimoSegundo = bytes ultimaVerificacao = Now() END END // Verifica se pode transferir mais bytes PROCEDURE PodeTransferir(bytes is int) : boolean IF bandaMaxima = 0 THEN RETURN True END RETURN (transferidoUltimoSegundo + bytes <= bandaMaxima) END END ``` Estas melhorias aprimorariam significativamente nossa implementação do WNetShare, incorporando as melhores práticas demonstradas no exemplo do fórum da PCSOFT, especialmente em termos de eficiência de transferência, gerenciamento de conexões e tolerância a falhas. -- Adriano José Boller ______________________________________________ Consultor e Representante Oficial da PcSoft no Brasil +55 (41) 99949 1800 adrianoboller@gmail.com skype: adrianobollerhttp://wxinformatica.com.br/