OverviewFilesCommitsIssuesDocsReleasesPeers

hyper-deploy commits / 3b0f009

Attach hyper-overlay/v2 on DeployServer connections (enableTrees)
Phase 0.5 follow-on to the 0.5b tree-publish pass. When a DeployServer is populated with trees (the default since 0.5b), it now also attaches hyper-overlay/v2 on each incoming swarm connection so clients can send tree-request and content-request messages alongside the existing file-list flow. New opts.enableTrees option (default true). Disabling reverts to the pre-0.5b file-list-only behaviour. Implementation: - Construct a single OverlayProtocolV2 instance at _open, with a minimal stub syncEngine whose _fileIndex is the server's own fileIndex (populated in _scan with tree + file entries) - On each _onConnection, build contentHashPaths + filePaths from the manifest and attach the overlay-v2 channel via Protomux.from(conn) - Protomux multiplexes cleanly — hyper-deploy's own protocol channel and hyper-overlay/v2 share one transport stream without interference Verified: - test/tree-publish.test.js — 7/7 pass (tree index populated; rootHash on manifest; stable across rescans) - test/e2e-release-sync.test.js — 3/3 pass (file-list flow unchanged) Client-side counterpart (pgh NetworkFetcher) ships in pear-git-v3. End-to-end wire test deferred to Phase 4 (stortron mirror validation). Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
3b0f00933bd0f057e3907c3b6d210b3413b8cf80
by plankatron <fleeky@gmail.com> · 2026-04-18T13:56:42.000Z

Changed files (1) +50 -0

index.js +50 -0
……@@ -25,10 +25,13 @@ import os from '#os'
2525import ReadyResource from 'ready-resource'
2626import safetyCatch from 'safety-catch'
2727
28import Protomux from 'protomux'
29
2830import { FileIndex } from 'hyper-overlay/file-index'
2931import { TransferManager } from 'hyper-overlay/transfer'
3032import { hashChunk } from 'hyper-overlay/chunker'
3133import { walkTree } from 'hyper-overlay/tree'
34import { OverlayProtocolV2 } from 'hyper-overlay/protocol-v2'
3235import { attachProtocol } from './lib/protocol.js'
3336
3437const CHUNK_THRESHOLD = 1048576 // 1 MB — files below this transfer as whole blobs
……@@ -72,6 +75,12 @@ export class DeployServer extends ReadyResource {
7275 this._discovery = null
7376 this._sessions = new Set()
7477
78 // 0.5b tree publish + 0.5c tree serving: when trees are populated
79 // (which we do in _scan), also attach hyper-overlay/v2 to each
80 // connection so clients can request trees + content-by-hash.
81 this._enableTrees = opts.enableTrees !== false
82 this._overlayProtocol = null
83
7584 this.manifest = null
7685 this.stats = { totalConnections: 0, filesServed: 0, bytesServed: 0 }
7786
……@@ -93,6 +102,23 @@ export class DeployServer extends ReadyResource {
93102 await this._fileIndex.ready()
94103 this._transferManager = new TransferManager(this._fileIndex)
95104
105 // Overlay-v2 protocol for tree-request / content-request. Shares
106 // the fileIndex with the file-list flow; no separate storage.
107 if (this._enableTrees) {
108 const stubSyncEngine = {
109 _fileIndex: this._fileIndex,
110 feedKey: '0'.repeat(64),
111 feed: { length: 0, async get () { return null } },
112 async markSynced () {},
113 async logPut () {}
114 }
115 this._overlayProtocol = new OverlayProtocolV2(
116 stubSyncEngine,
117 this._transferManager,
118 { key: this.topic, autoSync: false }
119 )
120 }
121
96122 // Index directory
97123 await this._scan()
98124
……@@ -216,6 +242,30 @@ export class DeployServer extends ReadyResource {
216242 return
217243 }
218244
245 // Also attach hyper-overlay/v2 on the same stream (protomux handles
246 // multiplexing). Populates contentHashPaths from the fileIndex so
247 // content-request can serve any file by its contentHash.
248 if (this._overlayProtocol) {
249 try {
250 const mux = Protomux.from(conn)
251 // Build content-hash → disk-path map so content-request works
252 const contentHashPaths = new Map()
253 const filePaths = new Map()
254 for (const f of (this.manifest && this.manifest.files) || []) {
255 if (f.hash) {
256 const diskPath = path.join(this.dir, f.path)
257 contentHashPaths.set(f.hash, diskPath)
258 filePaths.set(f.path, diskPath)
259 }
260 }
261 this._overlayProtocol._contentHashPaths = contentHashPaths
262 this._overlayProtocol._filePaths = filePaths
263 this._overlayProtocol.attach(mux)
264 } catch (err) {
265 this.emit('error', new Error('failed to attach overlay-v2 protocol: ' + err.message))
266 }
267 }
268
219269 const session = { peerKey, destroyed: false, filesServed: 0, bytesServed: 0 }
220270 this._sessions.add(session)
221271 this.emit('peer', { key: peerKey, state: 'connected' })