Skip to content

Commit 614e33d

Browse files
TakashiMatsudaStebalien
authored andcommitted
feature: 'ipfs swarm peering' command (#8147)
* feat: added swarm peering command supporting add, ls and rm Co-authored-by: Steven Allen <steven@stebalien.com> (cherry picked from commit a651045)
1 parent 90f65d2 commit 614e33d

File tree

5 files changed

+199
-0
lines changed

5 files changed

+199
-0
lines changed

core/commands/commands_test.go

+4
Original file line numberDiff line numberDiff line change
@@ -237,6 +237,10 @@ func TestCommands(t *testing.T) {
237237
"/swarm/filters/add",
238238
"/swarm/filters/rm",
239239
"/swarm/peers",
240+
"/swarm/peering",
241+
"/swarm/peering/add",
242+
"/swarm/peering/ls",
243+
"/swarm/peering/rm",
240244
"/tar",
241245
"/tar/add",
242246
"/tar/cat",

core/commands/swarm.go

+144
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,7 @@ ipfs peers in the internet.
5151
"disconnect": swarmDisconnectCmd,
5252
"filters": swarmFiltersCmd,
5353
"peers": swarmPeersCmd,
54+
"peering": swarmPeeringCmd,
5455
},
5556
}
5657

@@ -61,6 +62,149 @@ const (
6162
swarmDirectionOptionName = "direction"
6263
)
6364

65+
type peeringResult struct {
66+
ID peer.ID
67+
Status string
68+
}
69+
70+
var swarmPeeringCmd = &cmds.Command{
71+
Helptext: cmds.HelpText{
72+
Tagline: "Modify the peering subsystem.",
73+
ShortDescription: `
74+
'ipfs swarm peering' manages the peering subsystem.
75+
Peers in the peering subsystem is maintained to be connected, reconnected
76+
on disconnect with a back-off.
77+
The changes are not saved to the config.
78+
`,
79+
},
80+
Subcommands: map[string]*cmds.Command{
81+
"add": swarmPeeringAddCmd,
82+
"ls": swarmPeeringLsCmd,
83+
"rm": swarmPeeringRmCmd,
84+
},
85+
}
86+
87+
var swarmPeeringAddCmd = &cmds.Command{
88+
Helptext: cmds.HelpText{
89+
Tagline: "Add peers into the peering subsystem.",
90+
ShortDescription: `
91+
'ipfs swarm peering add' will add the new address to the peering subsystem as one that should always be connected to.
92+
`,
93+
},
94+
Arguments: []cmds.Argument{
95+
cmds.StringArg("address", true, true, "address of peer to add into the peering subsystem"),
96+
},
97+
Run: func(req *cmds.Request, res cmds.ResponseEmitter, env cmds.Environment) error {
98+
addrs := make([]ma.Multiaddr, len(req.Arguments))
99+
100+
for i, arg := range req.Arguments {
101+
addr, err := ma.NewMultiaddr(arg)
102+
if err != nil {
103+
return err
104+
}
105+
106+
addrs[i] = addr
107+
}
108+
109+
addInfos, err := peer.AddrInfosFromP2pAddrs(addrs...)
110+
if err != nil {
111+
return err
112+
}
113+
114+
node, err := cmdenv.GetNode(env)
115+
if err != nil {
116+
return err
117+
}
118+
119+
for _, addrinfo := range addInfos {
120+
node.Peering.AddPeer(addrinfo)
121+
err = res.Emit(peeringResult{addrinfo.ID, "success"})
122+
if err != nil {
123+
return err
124+
}
125+
}
126+
return nil
127+
},
128+
Encoders: cmds.EncoderMap{
129+
cmds.Text: cmds.MakeTypedEncoder(func(req *cmds.Request, w io.Writer, pr *peeringResult) error {
130+
fmt.Fprintf(w, "add %s %s\n", pr.ID.String(), pr.Status)
131+
return nil
132+
}),
133+
},
134+
Type: peeringResult{},
135+
}
136+
137+
var swarmPeeringLsCmd = &cmds.Command{
138+
Helptext: cmds.HelpText{
139+
Tagline: "List peers registered in the peering subsystem.",
140+
ShortDescription: `
141+
'ipfs swarm peering ls' lists the peers that are registered in the peering subsystem and to which the daemon is always connected.
142+
`,
143+
},
144+
Run: func(req *cmds.Request, res cmds.ResponseEmitter, env cmds.Environment) error {
145+
node, err := cmdenv.GetNode(env)
146+
if err != nil {
147+
return err
148+
}
149+
peers := node.Peering.ListPeers()
150+
return cmds.EmitOnce(res, addrInfos{Peers: peers})
151+
},
152+
Type: addrInfos{},
153+
Encoders: cmds.EncoderMap{
154+
cmds.Text: cmds.MakeTypedEncoder(func(req *cmds.Request, w io.Writer, ai *addrInfos) error {
155+
for _, info := range ai.Peers {
156+
fmt.Fprintf(w, "%s\n", info.ID)
157+
for _, addr := range info.Addrs {
158+
fmt.Fprintf(w, "\t%s\n", addr)
159+
}
160+
}
161+
return nil
162+
}),
163+
},
164+
}
165+
166+
type addrInfos struct {
167+
Peers []peer.AddrInfo
168+
}
169+
170+
var swarmPeeringRmCmd = &cmds.Command{
171+
Helptext: cmds.HelpText{
172+
Tagline: "Remove a peer from the peering subsystem.",
173+
ShortDescription: `
174+
'ipfs swarm peering rm' will remove the given ID from the peering subsystem and remove it from the always-on connection.
175+
`,
176+
},
177+
Arguments: []cmds.Argument{
178+
cmds.StringArg("ID", true, true, "ID of peer to remove from the peering subsystem"),
179+
},
180+
Run: func(req *cmds.Request, res cmds.ResponseEmitter, env cmds.Environment) error {
181+
node, err := cmdenv.GetNode(env)
182+
if err != nil {
183+
return err
184+
}
185+
186+
for _, arg := range req.Arguments {
187+
id, err := peer.Decode(arg)
188+
if err != nil {
189+
return err
190+
}
191+
192+
node.Peering.RemovePeer(id)
193+
if err = res.Emit(peeringResult{id, "success"}); err != nil {
194+
return err
195+
}
196+
}
197+
return nil
198+
},
199+
Type: peeringResult{},
200+
Encoders: cmds.EncoderMap{
201+
cmds.Text: cmds.MakeTypedEncoder(func(req *cmds.Request, w io.Writer, pr *peeringResult) error {
202+
fmt.Fprintf(w, "add %s %s\n", pr.ID.String(), pr.Status)
203+
return nil
204+
}),
205+
},
206+
}
207+
64208
var swarmPeersCmd = &cmds.Command{
65209
Helptext: cmds.HelpText{
66210
Tagline: "List peers with open connections.",

peering/peering.go

+11
Original file line numberDiff line numberDiff line change
@@ -242,6 +242,17 @@ func (ps *PeeringService) AddPeer(info peer.AddrInfo) {
242242
}
243243
}
244244

245+
// ListPeers lists peers in the peering service.
246+
func (ps *PeeringService) ListPeers() []peer.AddrInfo {
247+
out := make([]peer.AddrInfo, 0, len(ps.peers))
248+
for id, addrs := range ps.peers {
249+
ai := peer.AddrInfo{ID: id}
250+
ai.Addrs = append(ai.Addrs, addrs.addrs...)
251+
out = append(out, ai)
252+
}
253+
return out
254+
}
255+
245256
// RemovePeer removes a peer from the peering service. This function may be
246257
// safely called at any time: before the service is started, while running, or
247258
// after it stops.

peering/peering_test.go

+6
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,7 @@ func TestPeeringService(t *testing.T) {
3939

4040
// peer 1 -> 2
4141
ps1.AddPeer(peer.AddrInfo{ID: h2.ID(), Addrs: h2.Addrs()})
42+
require.Contains(t, ps1.ListPeers(), peer.AddrInfo{ID: h2.ID(), Addrs: h2.Addrs()})
4243

4344
// We haven't started so we shouldn't have any peers.
4445
require.Never(t, func() bool {
@@ -109,6 +110,7 @@ func TestPeeringService(t *testing.T) {
109110

110111
// Unprotect 2 from 1.
111112
ps1.RemovePeer(h2.ID())
113+
require.NotContains(t, ps1.ListPeers(), peer.AddrInfo{ID: h2.ID(), Addrs: h2.Addrs()})
112114

113115
// Trim connections.
114116
h1.ConnManager().TrimOpenConns(ctx)
@@ -127,7 +129,9 @@ func TestPeeringService(t *testing.T) {
127129

128130
// Until added back
129131
ps1.AddPeer(peer.AddrInfo{ID: h2.ID(), Addrs: h2.Addrs()})
132+
require.Contains(t, ps1.ListPeers(), peer.AddrInfo{ID: h2.ID(), Addrs: h2.Addrs()})
130133
ps1.AddPeer(peer.AddrInfo{ID: h3.ID(), Addrs: h3.Addrs()})
134+
require.Contains(t, ps1.ListPeers(), peer.AddrInfo{ID: h3.ID(), Addrs: h3.Addrs()})
131135
t.Logf("wait for h1 to connect to h2 and h3 again")
132136
require.Eventually(t, func() bool {
133137
return h1.Network().Connectedness(h2.ID()) == network.Connected
@@ -142,7 +146,9 @@ func TestPeeringService(t *testing.T) {
142146

143147
// Adding and removing should work after stopping.
144148
ps1.AddPeer(peer.AddrInfo{ID: h4.ID(), Addrs: h4.Addrs()})
149+
require.Contains(t, ps1.ListPeers(), peer.AddrInfo{ID: h4.ID(), Addrs: h4.Addrs()})
145150
ps1.RemovePeer(h2.ID())
151+
require.NotContains(t, ps1.ListPeers(), peer.AddrInfo{ID: h2.ID(), Addrs: h2.Addrs()})
146152
}
147153

148154
func TestNextBackoff(t *testing.T) {

test/sharness/t0140-swarm.sh

+34
Original file line numberDiff line numberDiff line change
@@ -97,6 +97,40 @@ test_expect_success "Addresses.NoAnnounce with /ipcidr affects addresses" '
9797

9898
test_kill_ipfs_daemon
9999

100+
test_launch_ipfs_daemon
101+
102+
test_expect_success "'ipfs swarm peering ls' lists peerings" '
103+
ipfs swarm peering ls
104+
'
105+
106+
peeringID='QmYyQSo1c1Ym7orWxLYvCrM2EmxFTANf8wXmmE7DWjhx5N'
107+
peeringID2='QmYyQSo1c1Ym7orWxLYvCrM2EmxFTANf8wXmmE7DWjhx5K'
108+
peeringAddr='/ip4/1.2.3.4/tcp/1234/p2p/QmYyQSo1c1Ym7orWxLYvCrM2EmxFTANf8wXmmE7DWjhx5N'
109+
peeringAddr2='/ip4/1.2.3.4/tcp/1234/p2p/QmYyQSo1c1Ym7orWxLYvCrM2EmxFTANf8wXmmE7DWjhx5K'
110+
test_expect_success "'ipfs swarm peering add' adds a peering" '
111+
ipfs swarm peering ls > peeringls &&
112+
! test_should_contain ${peeringID} peeringls &&
113+
! test_should_contain ${peeringID2} peeringls &&
114+
ipfs swarm peering add ${peeringAddr} ${peeringAddr2}
115+
'
116+
117+
test_expect_success 'a peering is added' '
118+
ipfs swarm peering ls > peeringadd &&
119+
test_should_contain ${peeringID} peeringadd &&
120+
test_should_contain ${peeringID2} peeringadd
121+
'
122+
123+
test_expect_success "'swarm peering rm' removes a peering" '
124+
ipfs swarm peering rm ${peeringID}
125+
'
126+
127+
test_expect_success 'peering is removed' '
128+
ipfs swarm peering ls > peeringrm &&
129+
! test_should_contain ${peeringID} peeringrm
130+
'
131+
132+
test_kill_ipfs_daemon
133+
100134
test_expect_success "set up tcp testbed" '
101135
iptb testbed create -type localipfs -count 2 -force -init
102136
'

0 commit comments

Comments
 (0)