Skip to content

Instantly share code, notes, and snippets.

@ViniciusFXavier
Last active July 6, 2026 19:19
Show Gist options
  • Select an option

  • Save ViniciusFXavier/1ada02737f563fd1034b1198cf169df0 to your computer and use it in GitHub Desktop.

Select an option

Save ViniciusFXavier/1ada02737f563fd1034b1198cf169df0 to your computer and use it in GitHub Desktop.
sync.js
#!/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)
})
{
"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"
}
}
@ViniciusFXavier

Copy link
Copy Markdown
Author

node index.js join 06127d57e8110173adcc6c6248f5dfb214d4daf72ce8680b232744c2cf63ddef C:\P2PSync

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment