Last active
July 6, 2026 19:19
-
-
Save ViniciusFXavier/1ada02737f563fd1034b1198cf169df0 to your computer and use it in GitHub Desktop.
sync.js
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| #!/usr/bin/env node | |
| 'use strict' | |
| const path = require('path') | |
| const fs = require('fs') | |
| const Corestore = require('corestore') | |
| const Hyperdrive = require('hyperdrive') | |
| const Hyperswarm = require('hyperswarm') | |
| const Localdrive = require('localdrive') | |
| const MirrorDrive = require('mirror-drive') | |
| const chokidar = require('chokidar') | |
| // --------------------------------------------------------------------------- | |
| // Configuração via linha de comando | |
| // | |
| // Peer que CRIA a partilha (host): | |
| // node index.js host [pasta] [pasta-storage] | |
| // | |
| // Peer que ENTRA usando a chave gerada pelo host: | |
| // node index.js join <chave> [pasta] [pasta-storage] | |
| // | |
| // Exemplos (Windows): | |
| // node index.js host C:\P2PSync | |
| // node index.js join 4f9a...b21c C:\P2PSync | |
| // --------------------------------------------------------------------------- | |
| const [, , mode, arg1, arg2, arg3] = process.argv | |
| const DEFAULT_FOLDER = process.platform === 'win32' | |
| ? path.join('C:\\', 'P2PSync') | |
| : path.join(require('os').homedir(), 'P2PSync') | |
| function usage() { | |
| console.log(` | |
| Uso: | |
| node index.js host [pasta] [storage] | |
| node index.js join <chave-hex> [pasta] [storage] | |
| Pasta padrão: ${DEFAULT_FOLDER} | |
| `) | |
| process.exit(1) | |
| } | |
| if (mode !== 'host' && mode !== 'join') usage() | |
| if (mode === 'join' && !arg1) usage() | |
| const folder = mode === 'host' ? (arg1 || DEFAULT_FOLDER) : (arg2 || DEFAULT_FOLDER) | |
| const storagePath = mode === 'host' ? (arg2 || './storage-host') : (arg3 || './storage-join') | |
| const shareKey = mode === 'join' ? arg1 : null | |
| fs.mkdirSync(folder, { recursive: true }) | |
| console.log(`[info] pasta local sincronizada: ${folder}`) | |
| console.log(`[info] storage do hypercore: ${path.resolve(storagePath)}`) | |
| async function main() { | |
| const store = new Corestore(storagePath) | |
| await store.ready() | |
| const drive = shareKey | |
| ? new Hyperdrive(store, Buffer.from(shareKey, 'hex')) | |
| : new Hyperdrive(store) | |
| await drive.ready() | |
| const topic = drive.discoveryKey | |
| const swarm = new Hyperswarm() | |
| swarm.on('connection', (conn, info) => { | |
| console.log(`[peer] conectado: ${info.publicKey.toString('hex').slice(0, 8)}...`) | |
| store.replicate(conn) | |
| conn.setKeepAlive?.(true) | |
| conn.setNoDelay?.(true) | |
| conn.on('error', (err) => console.log('[peer] erro de conexão:', err.message)) | |
| conn.on('close', () => console.log('[peer] desconectado')) | |
| }) | |
| swarm.join(topic, { server: true, client: true }) | |
| await swarm.flush().catch(() => { }) | |
| if (mode === 'host') { | |
| console.log('\n=== MODO HOST ===') | |
| console.log('Compartilhe esta chave com o outro peer:') | |
| console.log(drive.key.toString('hex')) | |
| console.log('==================\n') | |
| } else { | |
| console.log('\n[info] aguardando peer host para baixar os dados...\n') | |
| } | |
| const local = new Localdrive(folder) | |
| // ------------------------------------------------------------------- | |
| // Upload: pasta local -> hyperdrive (qualquer alteração local é enviada) | |
| // ------------------------------------------------------------------- | |
| let uploading = false | |
| async function uploadLocalToDrive(label) { | |
| if (uploading) return | |
| uploading = true | |
| try { | |
| const mirror = new MirrorDrive(local, drive) | |
| await mirror.done() | |
| const { add, change, remove } = mirror.count | |
| if (add || change || remove) { | |
| console.log(`[upload:${label}] +${add} ~${change} -${remove}`) | |
| } | |
| } catch (err) { | |
| console.log('[upload] erro:', err.message) | |
| } finally { | |
| uploading = false | |
| } | |
| } | |
| // ------------------------------------------------------------------- | |
| // Download: hyperdrive -> pasta local (traz o que os outros peers enviaram) | |
| // ------------------------------------------------------------------- | |
| let downloading = false | |
| async function downloadDriveToLocal(label) { | |
| if (downloading) return | |
| downloading = true | |
| try { | |
| const mirror = new MirrorDrive(drive, local) | |
| await mirror.done() | |
| const { add, change, remove } = mirror.count | |
| if (add || change || remove) { | |
| console.log(`[download:${label}] +${add} ~${change} -${remove}`) | |
| } | |
| } catch (err) { | |
| console.log('[download] erro:', err.message) | |
| } finally { | |
| downloading = false | |
| } | |
| } | |
| // Sincronização inicial | |
| await uploadLocalToDrive('inicial') | |
| await downloadDriveToLocal('inicial') | |
| // Observa mudanças na pasta local (arquivos que você adicionar/editar/remover) | |
| const watcher = chokidar.watch(folder, { | |
| ignoreInitial: true, | |
| awaitWriteFinish: { stabilityThreshold: 300, pollInterval: 100 } | |
| }) | |
| let pending = false | |
| watcher.on('all', () => { | |
| if (pending) return | |
| pending = true | |
| setTimeout(async () => { | |
| pending = false | |
| await uploadLocalToDrive('local->drive') | |
| }, 400) | |
| }) | |
| // Observa atualizações vindas de outros peers no hyperdrive | |
| drive.core.on('append', () => { | |
| console.log('[info] append - dados recebidos de outro peer, atualizando pasta local...') | |
| downloadDriveToLocal('drive->local').catch(() => { }) | |
| }) | |
| drive.core.on('download', () => { | |
| console.log('[info] download - dados recebidos de outro peer, atualizando pasta local...') | |
| downloadDriveToLocal('drive->local').catch(() => { }) | |
| }) | |
| process.on('SIGINT', async () => { | |
| console.log('\n[info] encerrando...') | |
| await watcher.close() | |
| await swarm.destroy() | |
| await drive.close() | |
| await store.close() | |
| console.log('[info] encerrado.') | |
| process.exit(0) | |
| }) | |
| } | |
| main().catch((err) => { | |
| console.error('[fatal]', err) | |
| process.exit(1) | |
| }) |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| { | |
| "name": "p2p-folder-sync", | |
| "version": "1.0.0", | |
| "description": "Sincronizacao de pastas ponto-a-ponto usando Hyperswarm + Hyperdrive (stack Holepunch)", | |
| "main": "index.js", | |
| "type": "commonjs", | |
| "scripts": { | |
| "start": "node index.js", | |
| "dev": "node index.js join 06127d57e8110173adcc6c6248f5dfb214d4daf72ce8680b232744c2cf63ddef C:\P2PSync" | |
| }, | |
| "dependencies": { | |
| "chokidar": "^3.6.0", | |
| "corestore": "^7.11.0", | |
| "hyperdrive": "^13.3.2", | |
| "hyperswarm": "^4.8.4", | |
| "localdrive": "^1.11.4", | |
| "mirror-drive": "^1.1.2" | |
| } | |
| } |
Author
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
node index.js join 06127d57e8110173adcc6c6248f5dfb214d4daf72ce8680b232744c2cf63ddef C:\P2PSync