feat: persistent multi-share configuration (shares.json + localStorage)
Daemon side: - internal/shares: new package reads/writes shares.json next to identity - proto: add ShareEntry type, add_share/remove_share/list_shares IPC commands, shares_list event, path field on FileEntry - netmgr: load shares.json on startup; ScanAllShares combines legacy ShareDir with shares.json entries (recursive walk with relative paths) - mesh: ScanFiles callback lets manager inject multi-share scanning without mesh knowing about shares.json - ipc: handle add_share, remove_share, list_shares commands Browser side: - ShareManager component replaces FolderPicker: shows list of named shares with remove/re-pick buttons; persists share records to waste_shares in localStorage (name, global flag, networkId) - FolderPicker retained for internal use; Sidebar now uses ShareManager Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -23,6 +23,7 @@ import (
|
||||
"github.com/waste-go/internal/invite"
|
||||
"github.com/waste-go/internal/netmgr"
|
||||
"github.com/waste-go/internal/proto"
|
||||
"github.com/waste-go/internal/shares"
|
||||
)
|
||||
|
||||
// RunWS starts a WebSocket IPC server on 127.0.0.1:wsPort.
|
||||
@@ -246,7 +247,7 @@ func handleClient(conn net.Conn, mgr *netmgr.Manager) {
|
||||
Type: proto.EvtFileList,
|
||||
NetworkID: n.ID,
|
||||
PeerID: ptr(n.Identity.PeerID()),
|
||||
Files: n.Mesh.ScanShareDir(),
|
||||
Files: mgr.ScanAllShares(n.ID),
|
||||
})
|
||||
} else {
|
||||
req, err := json.Marshal(proto.PeerMessage{Type: proto.MsgFileListReq})
|
||||
@@ -258,6 +259,35 @@ func handleClient(conn net.Conn, mgr *netmgr.Manager) {
|
||||
}
|
||||
}
|
||||
|
||||
case proto.CmdAddShare:
|
||||
if cmd.Path == "" {
|
||||
send(errMsg("add_share: path is required"))
|
||||
continue
|
||||
}
|
||||
networks := cmd.ShareNetworks
|
||||
if len(networks) == 0 {
|
||||
networks = []string{"*"}
|
||||
}
|
||||
if err := mgr.Shares.Add(shares.Share{Path: cmd.Path, Networks: networks}); err != nil {
|
||||
send(errMsg(fmt.Sprintf("add_share: %v", err)))
|
||||
continue
|
||||
}
|
||||
send(sharesListMsg(mgr))
|
||||
|
||||
case proto.CmdRemoveShare:
|
||||
if cmd.Path == "" {
|
||||
send(errMsg("remove_share: path is required"))
|
||||
continue
|
||||
}
|
||||
if err := mgr.Shares.Remove(cmd.Path); err != nil {
|
||||
send(errMsg(fmt.Sprintf("remove_share: %v", err)))
|
||||
continue
|
||||
}
|
||||
send(sharesListMsg(mgr))
|
||||
|
||||
case proto.CmdListShares:
|
||||
send(sharesListMsg(mgr))
|
||||
|
||||
case proto.CmdGenerateInvite:
|
||||
n := mgr.Resolve(cmd.NetworkID)
|
||||
if n == nil {
|
||||
@@ -389,6 +419,18 @@ func errMsg(s string) proto.IpcMessage {
|
||||
return proto.IpcMessage{Type: proto.EvtError, ErrorMessage: s}
|
||||
}
|
||||
|
||||
func sharesListMsg(mgr *netmgr.Manager) proto.IpcMessage {
|
||||
all := mgr.Shares.All()
|
||||
entries := make([]proto.ShareEntry, len(all))
|
||||
for i, sh := range all {
|
||||
entries[i] = proto.ShareEntry{Path: sh.Path, Networks: sh.Networks}
|
||||
}
|
||||
return proto.IpcMessage{Type: proto.EvtSharesList, Shares: entries}
|
||||
}
|
||||
|
||||
// ensure shares import is used
|
||||
var _ = shares.Share{}
|
||||
|
||||
func ptr[T any](v T) *T { return &v }
|
||||
|
||||
func randomHex(n int) string {
|
||||
|
||||
Reference in New Issue
Block a user