diff --git a/fs/rc/jobs/job.go b/fs/rc/jobs/job.go index deacd9105..e8b141ead 100644 --- a/fs/rc/jobs/job.go +++ b/fs/rc/jobs/job.go @@ -2,7 +2,9 @@ package jobs import ( + "bytes" "context" + "encoding/json" "errors" "fmt" "net/http" @@ -532,6 +534,32 @@ func NewJobFromParams(ctx context.Context, in rc.Params) (out rc.Params) { return out } +// NewJobFromBytes creates an rc job from a JSON blob as bytes. +// +// The JSON blob should contain a _path entry. +// +// It returns a JSON blob as output which may be an error. +func NewJobFromBytes(ctx context.Context, inBuf []byte) (outBuf []byte) { + var in rc.Params + var out rc.Params + + // Parse a JSON blob from the input + err := json.Unmarshal(inBuf, &in) + if err != nil { + out, _ = rc.Error("unknown", in, err, http.StatusBadRequest) + } else { + out = NewJobFromParams(ctx, in) + } + + var w bytes.Buffer + err = rc.WriteJSON(&w, out) + if err != nil { + fs.Errorf(nil, "rc: NewJobFromBytes: failed to write JSON output: %v", err) + return []byte(`{"error":"failed to write JSON output"}`) + } + return w.Bytes() +} + func init() { rc.Add(rc.Call{ Path: "job/batch", diff --git a/fs/rc/jobs/job_test.go b/fs/rc/jobs/job_test.go index d29252534..e06ba467f 100644 --- a/fs/rc/jobs/job_test.go +++ b/fs/rc/jobs/job_test.go @@ -702,6 +702,58 @@ func TestNewJobFromParams(t *testing.T) { } } +func TestNewJobFromBytes(t *testing.T) { + ctx := context.Background() + for _, test := range []struct { + in string + want string + }{{ + in: `{ + "_path": "rc/noop", + "a": "potato" +}`, + want: `{ + "a": "potato" +} +`, + }, { + in: `{ + "_path": "rc/error", + "e": "sausage" + }`, + want: `{ + "error": "arbitrary error on input map[e:sausage]", + "input": { + "e": "sausage" + }, + "path": "rc/error", + "status": 500 +} +`, + }, { + in: `parse error`, + want: `{ + "error": "invalid character 'p' looking for beginning of value", + "input": null, + "path": "unknown", + "status": 400 +} +`, + }, { + in: `"just a string"`, + want: `{ + "error": "json: cannot unmarshal string into Go value of type rc.Params", + "input": null, + "path": "unknown", + "status": 400 +} +`, + }} { + got := NewJobFromBytes(ctx, []byte(test.in)) + assert.Equal(t, test.want, string(got)) + } +} + func TestJobsBatch(t *testing.T) { ctx := context.Background()