update handlers

This commit is contained in:
Cadey Ratio 2019-12-13 11:48:03 +00:00
parent 49c1f3b766
commit 50c4184efa
5 changed files with 176 additions and 20 deletions

View File

@ -23,9 +23,12 @@ func (handlerDeleteCmd) Usage() string {
$ wasmcloud delete filename.wasm
Deletes a handler on wasmcloud. Please run this with care. No data loss will
happen, but support will need to be contacted.
happen, but support will need to be contacted if you want to un-delete a
handler.
Flags:
See the following command for a list of your deleted handlers:
$ wasmcloud list -show-deleted
`
}

View File

@ -0,0 +1,95 @@
package main
import (
"bytes"
"context"
"encoding/json"
"flag"
"fmt"
"io"
"io/ioutil"
"log"
"net/http"
"os"
"time"
"github.com/google/subcommands"
"tulpa.dev/within/wasmcloud/cmd/internal"
)
type handlerUpdateCmd struct {
abi string
}
func (handlerUpdateCmd) Name() string { return "update" }
func (handlerUpdateCmd) Synopsis() string { return "update a handler" }
func (handlerUpdateCmd) Usage() string {
return `wasmcloud update [options] <filename.wasm>
$ wasmcloud update shaman-of-hearts-23813 filename.wasm
Updates a handler on wasmcloud. Returns new details about the handler.
Flags:
`
}
func (h *handlerUpdateCmd) SetFlags(fs *flag.FlagSet) {
fs.StringVar(&h.abi, "abi", "cwa", "WebAssembly ABI to use for the handler")
}
func (h handlerUpdateCmd) Execute(ctx context.Context, fs *flag.FlagSet, _ ...interface{}) subcommands.ExitStatus {
if fs.NArg() != 2 {
fmt.Println("usage: wasmcloud update [options] <handler-name> <filename>")
return subcommands.ExitUsageError
}
hname := fs.Arg(0)
fname := fs.Arg(1)
data, err := ioutil.ReadFile(fname)
if err != nil {
log.Fatal(err)
}
hdlr := internal.Handler{
ABI: h.abi,
WASM: data,
}
bodyData, _ := json.Marshal(hdlr)
req, err := http.NewRequestWithContext(ctx, http.MethodPost, *apiServer+"/api/handler/update?name="+hname, bytes.NewBuffer(bodyData))
if err != nil {
log.Fatal(err)
}
withAPI(req)
resp, err := http.DefaultClient.Do(req)
if err != nil {
log.Fatal(err)
}
if resp.StatusCode != http.StatusOK {
io.Copy(os.Stdout, resp.Body)
return subcommands.ExitFailure
}
type apiResp struct {
ID int `json:"ID"`
CreatedAt time.Time `json:"CreatedAt"`
UpdatedAt time.Time `json:"UpdatedAt"`
Name string `json:"Name"`
Path string `json:"Path"`
}
var result apiResp
err = json.NewDecoder(resp.Body).Decode(&result)
resp.Body.Close()
if err != nil {
log.Fatal(err)
}
fmt.Println("updated handler")
fmt.Printf("name: %s\nIPFS ID: %s\n", result.Name, result.Path)
return subcommands.ExitSuccess
}

View File

@ -27,6 +27,7 @@ func main() {
subcommands.Register(&handlerListCmd{}, "handlers")
subcommands.Register(&handlerLogsCmd{}, "handlers")
subcommands.Register(&handlerInvokeCmd{}, "handlers")
subcommands.Register(&handlerUpdateCmd{}, "handlers")
subcommands.Register(namegenCmd{}, "utils")
subcommands.Register(&runCmd{}, "utils")

View File

@ -3,6 +3,7 @@ package main
import (
"bytes"
"encoding/json"
"fmt"
"io/ioutil"
"net/http"
"time"
@ -37,6 +38,77 @@ func deleteHandler(w http.ResponseWriter, r *http.Request, u *User) {
w.WriteHeader(http.StatusNoContent)
}
func updateHandler(w http.ResponseWriter, r *http.Request, u *User) {
ctx := r.Context()
q := r.URL.Query()
name := q.Get("name")
if name == "" {
http.NotFound(w, r)
return
}
var hdlr Handler
err := db.Where("name = ? AND user_id = ?", name, u.ID).First(&hdlr).Error
if err != nil {
ln.Error(ctx, err)
http.NotFound(w, r)
return
}
data, err := ioutil.ReadAll(http.MaxBytesReader(w, r.Body, 16*1024*1024))
if err != nil {
ln.Error(ctx, err)
http.Error(w, "invalid data", http.StatusBadRequest)
return
}
r.Body.Close()
var uHdlr internal.Handler
err = json.Unmarshal(data, &uHdlr)
if err != nil {
ln.Error(ctx, err)
http.Error(w, "not json", http.StatusBadRequest)
return
}
cid, err := uploadHandler(uHdlr)
if err != nil {
ln.Error(ctx, err)
http.Error(w, "wasm validation failure", http.StatusBadRequest)
return
}
hdlr.Path = cid
if err := db.Save(&hdlr).Error; err != nil {
ln.Error(ctx, err)
http.Error(w, "database error, contact support", http.StatusInternalServerError)
return
}
}
func uploadHandler(hdlr internal.Handler) (string, error) {
sh := shell.NewShell(*ipfsURL)
switch string(hdlr.ABI) {
case string(internal.CWA), string(internal.Dagger):
default:
return "", fmt.Errorf("unsupported ABI %s", hdlr.ABI)
}
buf := bytes.NewBuffer(hdlr.WASM)
_, err := wasm.DecodeModule(buf)
if err != nil {
return "", fmt.Errorf("can't decode module: %w", err)
}
cid, err := sh.Add(bytes.NewBuffer(hdlr.WASM))
if err != nil {
return "", fmt.Errorf("can't upload module to IPFS: %w", err)
}
return cid, nil
}
func createHandler(w http.ResponseWriter, r *http.Request, u *User) {
if !u.CanCreateHandlers {
http.Error(w, "you can't create handlers, contact support", http.StatusForbidden)
@ -44,7 +116,6 @@ func createHandler(w http.ResponseWriter, r *http.Request, u *User) {
}
ctx := r.Context()
sh := shell.NewShell(*ipfsURL)
data, err := ioutil.ReadAll(http.MaxBytesReader(w, r.Body, 16*1024*1024))
if err != nil {
ln.Error(ctx, err)
@ -61,25 +132,10 @@ func createHandler(w http.ResponseWriter, r *http.Request, u *User) {
return
}
switch string(hdlr.ABI) {
case string(internal.CWA), string(internal.Dagger):
default:
ln.Log(ctx, ln.Info("unknown ABI"), ln.F{"abi": hdlr.ABI})
http.Error(w, "unknown ABI", http.StatusBadRequest)
return
}
buf := bytes.NewBuffer(hdlr.WASM)
_, err = wasm.DecodeModule(buf)
cid, err := uploadHandler(hdlr)
if err != nil {
ln.Error(ctx, err)
http.Error(w, "not webassembly", http.StatusBadRequest)
}
cid, err := sh.Add(bytes.NewBuffer(hdlr.WASM))
if err != nil {
ln.Error(ctx, err)
http.Error(w, "can't upload wasm to storage", http.StatusInternalServerError)
http.Error(w, "wasm validation error", http.StatusBadRequest)
return
}

View File

@ -59,6 +59,7 @@ func main() {
rtr.HandleFunc("/api/handler", makeHandler(true, listHandlers)).Methods(http.MethodGet)
rtr.HandleFunc("/api/handler/delete", makeHandler(true, deleteHandler)).Methods(http.MethodDelete)
rtr.HandleFunc("/api/handler/create", makeHandler(true, createHandler)).Methods(http.MethodPost)
rtr.HandleFunc("/api/handler/update", makeHandler(true, updateHandler)).Methods(http.MethodPost)
rtr.HandleFunc("/api/handler/logs", makeHandler(true, getLogs)).Methods(http.MethodGet)
rtr.HandleFunc("/api/whoami", makeHandler(true, apiWhoami))