+ +
+ID | +Status | +Task | +Schedule | +
---|
+ +
++ +
++ This section is not complete yet. +
diff --git a/.gitignore b/.gitignore index 1fa6eb99..b3895239 100644 --- a/.gitignore +++ b/.gitignore @@ -1,5 +1,8 @@ dealbot.toml *~ +controller/static/script.js +node_modules + # Binaries for programs and plugins *.exe diff --git a/Dockerfile b/Dockerfile index 336356e2..68513c34 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,3 +1,9 @@ +# run npm install in a container with node. +FROM node:14-alpine AS js +WORKDIR /usr/src/app +COPY ./controller/app . +RUN npm install + FROM golang:alpine AS builder RUN apk update RUN apk upgrade @@ -6,8 +12,10 @@ RUN apk add --update gcc>=9.3.0 g++>=9.3.0 alpine-sdk WORKDIR /go/src/app/ COPY . . +COPY --from=js /usr/src/app ./controller/app # Fetch dependencies. RUN go get -d -v ./... +RUN go generate ./... RUN go build -o dealbot -ldflags "-X github.com/filecoin-project/dealbot/controller.buildDate=`date -u +%d/%m/%Y@%H:%M:%S`" ./ FROM alpine @@ -16,4 +24,4 @@ COPY --from=builder /go/src/app/dealbot /dealbot ENV DEALBOT_LOG_JSON=true ENV DEALBOT_WORKERS=10 ENV STAGE_TIMEOUT=DefaultStorage=48h,DefaultRetrieval=48h -ENTRYPOINT ["/dealbot"] \ No newline at end of file +ENTRYPOINT ["/dealbot"] diff --git a/commands/flags.go b/commands/flags.go index 95ee1978..59a26ac1 100644 --- a/commands/flags.go +++ b/commands/flags.go @@ -261,6 +261,10 @@ var ControllerFlags = []cli.Flag{ Usage: "set an access secret for access to inprogress data over gql", EnvVars: []string{"DEALBOT_GRAPHQL_ACCESS_TOKEN"}, }), + altsrc.NewStringFlag(&cli.StringFlag{ + Name: "devAssetDir", + Usage: "build frontend assets from directory instead of embedded version (set to location of 'controller'; the directory containing static and app)", + }), } var AllFlags = append(DealFlags, append(SingleTaskFlags, append(DaemonFlags, append(ControllerFlags, MockFlags...)...)...)...) diff --git a/controller/app/index.js b/controller/app/index.js new file mode 100644 index 00000000..792f0a28 --- /dev/null +++ b/controller/app/index.js @@ -0,0 +1,94 @@ +import "./jquery-global"; +import "bootstrap-cron-picker/dist/cron-picker"; + +$().ready(() => { + $('#newSchedule').cronPicker(); + + $("#addDone").hide(); + if ($('#newSR').is(':checked')) { + $("#newstorage").hide(); + } else { + $("#newretrieval").hide(); + } + $("#newSR").on('change', () => { + if ($('#newSR').is(':checked')) { + $("#newretrieval").show(); + $("#newstorage").hide(); + } else { + $("#newretrieval").hide(); + $("#newstorage").show(); + } + }) + + if (!$('#newRepeat').is(':checked')) { + $("#setschedule").hide(); + } + $("#newRepeat").on('change', () => { + if ($('#newRepeat').is(':checked')) { + $("#setschedule").show(); + } else { + $("#setschedule").hide(); + } + }) + + $("#addtask button").on('click', doSubmit); + $("schedulesection form").on('submit', doSubmit); +}) + +function doSubmit(e) { + if (e.preventDefault) { + e.preventDefault() + } + + // loop over miners + let miners = $("#newMiner").val().trim().split('\n') + + let remaining = miners.length; + let done = () => { + remaining--; + if (!remaining) { + $("#addDone").show() + } + } + + for (let i = 0; i < miners.length; i++) { + let miner = miners[i]; + let url = "/tasks/storage"; + let data = {}; + if ($('#newSR').is(':checked')) { + url = "/tasks/retrieval"; + data = { + "Miner": miner, + "PayloadCID": $('#newCid').val(), + "CARExport": false, + "MaxPriceAttoFIL": 20000000000, + } + } else { + data = { + "Miner": miner, + "Size": $('#newSize').val(), + "StartOffset": 6152, // 3 days? + "FastRetrieval": $('#newFast').is(':checked'), + "Verified": $('#newVerified').is(':checked'), + "MaxPriceAttoFIL": 20000000000, + } + } + + if ($('#newRepeat').is(':checked')) { + data.Schedule = $('#newSchedule').val() + data.ScheduleLimit = $('#newScheduleLimit').val() + } + if ($('#newScheduleTag').val() !='') { + data.Tag = $('#newScheduleTag').val() + } + + $.ajax({ + type: "POST", + url: url, + data: data, + success: done, + }); + } + + return false +} diff --git a/controller/app/jquery-global.js b/controller/app/jquery-global.js new file mode 100644 index 00000000..eb71c691 --- /dev/null +++ b/controller/app/jquery-global.js @@ -0,0 +1,3 @@ +import jquery from 'jquery'; +window.jQuery = jquery; +window.$ = jquery; diff --git a/controller/app/package-lock.json b/controller/app/package-lock.json new file mode 100644 index 00000000..91de01ca --- /dev/null +++ b/controller/app/package-lock.json @@ -0,0 +1,30 @@ +{ + "name": "dealbot-controller", + "version": "1.0.0", + "lockfileVersion": 1, + "requires": true, + "dependencies": { + "bootstrap": { + "version": "3.4.1", + "resolved": "https://registry.npmjs.org/bootstrap/-/bootstrap-3.4.1.tgz", + "integrity": "sha512-yN5oZVmRCwe5aKwzRj6736nSmKDX7pLYwsXiCj/EYmo16hODaBiT4En5btW/jhBF/seV+XMx3aYwukYC3A49DA==", + "dev": true + }, + "bootstrap-cron-picker": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/bootstrap-cron-picker/-/bootstrap-cron-picker-1.0.0.tgz", + "integrity": "sha1-fiTVFfLHWXgsmyr0mFVzDGlSYdE=", + "dev": true, + "requires": { + "bootstrap": "^3.3.7", + "jquery": "^3.2.1" + } + }, + "jquery": { + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/jquery/-/jquery-3.6.0.tgz", + "integrity": "sha512-JVzAR/AjBvVt2BmYhxRCSYysDsPcssdmTFnzyLEts9qNwmjmu4JTAMYubEfwVOSwpQ1I1sKKFcxhZCI2buerfw==", + "dev": true + } + } +} diff --git a/controller/app/package.json b/controller/app/package.json new file mode 100644 index 00000000..b87ff3e7 --- /dev/null +++ b/controller/app/package.json @@ -0,0 +1,23 @@ +{ + "name": "dealbot-controller", + "version": "1.0.0", + "description": "dealbot controller webapp logic", + "main": "index.js", + "scripts": { + "test": "echo \"Error: no test specified\" && exit 1" + }, + "repository": { + "type": "git", + "url": "git+https://github.com/filecoin-project/dealbot.git" + }, + "author": "Protocol Labs", + "license": "MIT", + "bugs": { + "url": "https://github.com/filecoin-project/dealbot/issues" + }, + "homepage": "https://github.com/filecoin-project/dealbot#readme", + "devDependencies": { + "bootstrap-cron-picker": "^1.0.0", + "jquery": "^3.6.0" + } +} diff --git a/controller/controller.go b/controller/controller.go index 4db3b69a..7efbbd2e 100644 --- a/controller/controller.go +++ b/controller/controller.go @@ -1,18 +1,23 @@ +//go:generate go run ./webutil/gen app static/script.js + package controller import ( "context" "embed" "fmt" + "io" "io/fs" "io/ioutil" "net" "net/http" "os" + "path" "time" "github.com/filecoin-project/dealbot/controller/graphql" "github.com/filecoin-project/dealbot/controller/state" + "github.com/filecoin-project/dealbot/controller/webutil" "github.com/filecoin-project/dealbot/metrics" metricslog "github.com/filecoin-project/dealbot/metrics/log" "github.com/filecoin-project/dealbot/metrics/prometheus" @@ -101,12 +106,7 @@ func New(ctx *cli.Context) (*Controller, error) { return nil, err } - gqlToken := "" - if ctx.IsSet("gqlAccessToken") { - gqlToken = ctx.String("gqlAccessToken") - } - - return NewWithDependencies(l, gl, gqlToken, recorder, backend) + return NewWithDependencies(ctx, l, gl, recorder, backend) } type logEcapsulator struct { @@ -121,7 +121,7 @@ func (fw *logEcapsulator) Write(p []byte) (n int, err error) { //go:embed static var static embed.FS -func NewWithDependencies(listener, graphqlListener net.Listener, gqlToken string, recorder metrics.MetricsRecorder, backend state.State) (*Controller, error) { +func NewWithDependencies(ctx *cli.Context, listener, graphqlListener net.Listener, recorder metrics.MetricsRecorder, backend state.State) (*Controller, error) { srv := new(Controller) srv.db = backend @@ -156,7 +156,18 @@ func NewWithDependencies(listener, graphqlListener net.Listener, gqlToken string if metricsHandler != nil { r.Handle("/metrics", metricsHandler) } - r.PathPrefix("/").Handler(http.FileServer(http.FS(statDir))) + + if ctx.IsSet("devAssetDir") { + scriptResolver := func(w http.ResponseWriter, r *http.Request) { + data := webutil.Compile(path.Join(ctx.String("devAssetDir"), "app"), false) + w.Header().Set("Content-Type", "application/json") + io.WriteString(w, data) + } + r.HandleFunc("/script.js", scriptResolver) + r.PathPrefix("/").Handler(http.FileServer(http.Dir(path.Join(ctx.String("devAssetDir"), "static")))) + } else { + r.PathPrefix("/").Handler(http.FileServer(http.FS(statDir))) + } srv.doneCh = make(chan struct{}) srv.server = &http.Server{ @@ -166,7 +177,7 @@ func NewWithDependencies(listener, graphqlListener net.Listener, gqlToken string } if graphqlListener != nil { - gqlHandler, err := graphql.GetHandler(srv.db, gqlToken) + gqlHandler, err := graphql.GetHandler(srv.db, ctx.String("gqlAccessToken")) if err != nil { return nil, err } diff --git a/controller/http_test.go b/controller/http_test.go index 208514e3..fe8bfe4c 100644 --- a/controller/http_test.go +++ b/controller/http_test.go @@ -4,6 +4,7 @@ import ( "bytes" "context" "encoding/json" + "flag" "fmt" "io" "io/ioutil" @@ -21,6 +22,7 @@ import ( "github.com/ipld/go-ipld-prime/codec/dagjson" "github.com/libp2p/go-libp2p-core/crypto" "github.com/stretchr/testify/require" + "github.com/urfave/cli/v2" ) const jsonTestDeals = "../devnet/sample_tasks.json" @@ -316,7 +318,8 @@ func newHarness(ctx context.Context, t *testing.T) *harness { require.NoError(t, err) be, err := state.NewStateDB(ctx, "sqlite", h.dbloc+"/tmp.sqlite", pr, h.recorder) require.NoError(t, err) - h.controller, err = controller.NewWithDependencies(listener, nil, "", h.recorder, be) + cc := cli.NewContext(cli.NewApp(), &flag.FlagSet{}, nil) + h.controller, err = controller.NewWithDependencies(cc, listener, nil, h.recorder, be) h.serveErr = make(chan error, 1) go func() { diff --git a/controller/state/statedb.go b/controller/state/statedb.go index 508ee601..c9ef6ac6 100644 --- a/controller/state/statedb.go +++ b/controller/state/statedb.go @@ -877,7 +877,7 @@ func (s *stateDB) PublishRecordsFrom(ctx context.Context, worker string) error { if err != nil { return err } - tskBuilder := tasks.Type.FinishedTask.NewBuilder() + tskBuilder := tasks.Type.FinishedTask__Repr.NewBuilder() if err := dagjson.Decoder(tskBuilder, rcrdRdr); err != nil { return err } diff --git a/controller/static/index.html b/controller/static/index.html index aae7800d..176feaa6 100644 --- a/controller/static/index.html +++ b/controller/static/index.html @@ -1,22 +1,133 @@ - + +
ID | +Status | +Task | +Schedule | +
---|