Skip to content

Commit e426088

Browse files
committed
refactor(pubsub): make pub command read from a file
We want to send payload in the body as multipart so users can use existing tools like curl for publishing arbitrary bytes to a topic. StringArg was created for "one message per line" use case, and if data has `\n` or `\r\n` byte sequences, it will cause payload to be split. It is not possible to undo this, because mentioned sequences are lost, so we are not able to tell if it was `\n` or `\r\n` We already avoid this problem in `block put` and `dht put` by reading payload via FileArg which does not mangle binary data and send it as-is. It feel like `pubsub pub` should be using it in the first place anyway, so this commit replaces StringArg with FileArg. This also closes ipfs#8454 and makes rpc in go-ipfs easier to code against.
1 parent 5bd282d commit e426088

File tree

2 files changed

+26
-31
lines changed

2 files changed

+26
-31
lines changed

core/commands/pubsub.go

Lines changed: 22 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,6 @@ import (
66
"io"
77
"io/ioutil"
88
"net/http"
9-
"os"
109
"sort"
1110

1211
cmdenv "github.com/ipfs/go-ipfs/core/commands/cmdenv"
@@ -146,41 +145,32 @@ TOPIC AND DATA ENCODING
146145

147146
var PubsubPubCmd = &cmds.Command{
148147
Helptext: cmds.HelpText{
149-
Tagline: "Publish a message to a given pubsub topic.",
148+
Tagline: "Publish data to a given pubsub topic.",
150149
ShortDescription: `
151150
ipfs pubsub pub publishes a message to a specified topic.
151+
It reads binary data from stdin or a file.
152152
153153
EXPERIMENTAL FEATURE
154154
155155
It is not intended in its current state to be used in a production
156156
environment. To use, the daemon must be run with
157157
'--enable-pubsub-experiment'.
158158
159-
TOPIC AND DATA ENCODING
159+
HTTP RPC ENCODING
160+
161+
The data to be published is sent in HTTP request body as multipart/form-data.
160162
161163
Topic names are a binary data too. To ensure all bytes are transferred
162-
correctly RPC client and server will use multibase encoding behind
163-
the scenes.
164+
correctly via URL params, the RPC client and server will use multibase
165+
encoding behind the scenes.
164166
165-
You can inspect the format by passing --enc=json. ipfs multibase commands
166-
can be used for encoding/decoding multibase strings in the userland.
167167
`,
168168
},
169169
Arguments: []cmds.Argument{
170170
cmds.StringArg("topic", true, false, "Topic to publish to."),
171-
cmds.StringArg("data", false, true, "Payload of message to publish."),
172-
},
173-
PreRun: func(req *cmds.Request, env cmds.Environment) error {
174-
// when there are no string args with data, read from stdin.
175-
if len(req.Arguments) == 1 {
176-
buf, err := ioutil.ReadAll(os.Stdin)
177-
if err != nil {
178-
return err
179-
}
180-
req.Arguments = append(req.Arguments, string(buf))
181-
}
182-
return urlArgsEncoder(req, env)
171+
cmds.FileArg("data", true, false, "The data to be published.").EnableStdin(),
183172
},
173+
PreRun: urlArgsEncoder,
184174
Run: func(req *cmds.Request, res cmds.ResponseEmitter, env cmds.Environment) error {
185175
api, err := cmdenv.GetApi(env, req)
186176
if err != nil {
@@ -191,13 +181,20 @@ TOPIC AND DATA ENCODING
191181
}
192182

193183
topic := req.Arguments[0]
194-
for _, data := range req.Arguments[1:] {
195-
if err := api.PubSub().Publish(req.Context, topic, []byte(data)); err != nil {
196-
return err
197-
}
184+
185+
// read data passed as a file
186+
file, err := cmdenv.GetFileArg(req.Files.Entries())
187+
if err != nil {
188+
return err
189+
}
190+
defer file.Close()
191+
data, err := ioutil.ReadAll(file)
192+
if err != nil {
193+
return err
198194
}
199195

200-
return nil
196+
// publish
197+
return api.PubSub().Publish(req.Context, topic, data)
201198
},
202199
}
203200

@@ -333,6 +330,7 @@ TOPIC AND DATA ENCODING
333330
},
334331
}
335332

333+
// TODO: move to cmdenv?
336334
// Encode binary data to be passed as multibase string in URL arguments.
337335
// (avoiding issues described in https://github.com/ipfs/go-ipfs/issues/7939)
338336
func urlArgsEncoder(req *cmds.Request, env cmds.Environment) error {
@@ -346,10 +344,6 @@ func urlArgsEncoder(req *cmds.Request, env cmds.Environment) error {
346344
// Decode binary data passed as multibase string in URL arguments.
347345
// (avoiding issues described in https://github.com/ipfs/go-ipfs/issues/7939)
348346
func urlArgsDecoder(req *cmds.Request, env cmds.Environment) error {
349-
err := req.ParseBodyArgs()
350-
if err != nil {
351-
return err
352-
}
353347
for n, arg := range req.Arguments {
354348
encoding, data, err := mbase.Decode(arg)
355349
if err != nil {

test/sharness/t0180-pubsub.sh

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -50,8 +50,9 @@ run_pubsub_tests() {
5050
test_cmp peers_exp peers_out
5151
'
5252

53-
test_expect_success "publish something" '
54-
ipfsi 1 pubsub pub testTopic "testOK" &> pubErr
53+
test_expect_success "publish something from file" '
54+
echo -n "testOK" > payload-file &&
55+
ipfsi 1 pubsub pub testTopic payload-file &> pubErr
5556
'
5657

5758
test_expect_success "wait until echo > wait executed" '
@@ -79,7 +80,7 @@ run_pubsub_tests() {
7980
go-sleep 500ms
8081
'
8182

82-
test_expect_success "publish something" '
83+
test_expect_success "publish something from stdin" '
8384
echo -n "testOK2" | ipfsi 3 pubsub pub testTopic &> pubErr
8485
'
8586

0 commit comments

Comments
 (0)