feat(wasm): expose taildrive WebDAV server and listDrivePeers via JS bridge
Add drive.go (build tag !ts_omit_drive): implements drive.FileSystemForRemote with a JS-backed handler. Streams request bodies chunk-by-chunk via readBodyChunk() and response bodies via write()/end() callbacks so no full-body buffering occurs regardless of file size. The handler is nil-safe: returns 404 until setDriveHandler() is called from JS. Add drive_stub.go (build tag ts_omit_drive): no-op stubs for stripped builds. Add peer.go: extract buildPeerAPIURL helper (previously inline in run()). Modify wasm_js.go: call initDriveForRemote before NewLocalBackend (SubSystem is set-once), expose setDriveHandler and listDrivePeers via wireDriveJS, and refactor the inline peerAPI URL logic to use buildPeerAPIURL. listDrivePeers mirrors native driveRemotesFromPeers: returns empty if DriveAccessEnabled() is false, then filters peers by PeerCapabilityTaildriveSharer using lb.PeerCaps(addr).HasCapability() (the live ACL-derived cap map). Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -158,6 +158,10 @@ func newIPN(jsConfig js.Value) map[string]any {
|
||||
sys.Tun.Get().Start()
|
||||
|
||||
logid := lpc.PublicID
|
||||
|
||||
// initDriveForRemote must be called before NewLocalBackend (SubSystem is set-once).
|
||||
driveFS := initDriveForRemote(sys)
|
||||
|
||||
srv := ipnserver.New(logf, logid, sys.Bus.Get(), sys.NetMon.Get())
|
||||
lb, err := ipnlocal.NewLocalBackend(logf, logid, sys, controlclient.LoginEphemeral)
|
||||
if err != nil {
|
||||
@@ -182,7 +186,7 @@ func newIPN(jsConfig js.Value) map[string]any {
|
||||
}
|
||||
lb.SetTCPHandlerForFunnelFlow(jsIPN.handleFunnelTCP)
|
||||
|
||||
return map[string]any{
|
||||
m := map[string]any{
|
||||
"run": js.FuncOf(func(this js.Value, args []js.Value) any {
|
||||
if len(args) != 1 {
|
||||
log.Fatal(`Usage: run({
|
||||
@@ -373,6 +377,8 @@ func newIPN(jsConfig js.Value) map[string]any {
|
||||
return jsIPN.localAPI(args[0].String(), args[1].String(), body)
|
||||
}),
|
||||
}
|
||||
wireDriveJS(jsIPN, driveFS, m)
|
||||
return m
|
||||
}
|
||||
|
||||
type jsIPN struct {
|
||||
@@ -482,32 +488,7 @@ func (i *jsIPN) run(jsCallbacks js.Value) {
|
||||
}
|
||||
|
||||
// Peer peerAPI URL from the peer's advertised Services.
|
||||
peerURL := ""
|
||||
var pp4, pp6 uint16
|
||||
for _, s := range p.Hostinfo().Services().All() {
|
||||
switch s.Proto {
|
||||
case tailcfg.PeerAPI4:
|
||||
pp4 = s.Port
|
||||
case tailcfg.PeerAPI6:
|
||||
pp6 = s.Port
|
||||
}
|
||||
}
|
||||
if selfHave4 && pp4 != 0 {
|
||||
for _, a := range p.Addresses().All() {
|
||||
if a.IsSingleIP() && a.Addr().Is4() {
|
||||
peerURL = fmt.Sprintf("http://%v", netip.AddrPortFrom(a.Addr(), pp4))
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
if peerURL == "" && selfHave6 && pp6 != 0 {
|
||||
for _, a := range p.Addresses().All() {
|
||||
if a.IsSingleIP() && a.Addr().Is6() {
|
||||
peerURL = fmt.Sprintf("http://%v", netip.AddrPortFrom(a.Addr(), pp6))
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
peerURL := buildPeerAPIURL(p, selfHave4, selfHave6)
|
||||
|
||||
return jsNetMapPeerNode{
|
||||
jsNetMapNode: jsNetMapNode{
|
||||
|
||||
Reference in New Issue
Block a user