Example #1
0
// HTTP handler for Flow Update
func (h *handler) handlePutFlowDef() error {

	// derive flow def key from  URL path
	flowDefKey := h.PathVar("flowDefKey")
	base.Logf("Flow Definition Key: ", flowDefKey)

	if flowDefKey == "" {
		return base.HTTPErrorf(http.StatusBadRequest, "Invalid Flow Def Key")
	}
	//
	wf := db.NewWorkflowDef(flowDefKey)

	// read JSON HTTP input into Object
	_, err := h.readObject(&wf)

	//base.Logf("Encoding Workflow Def ..%s",wf)
	data, _ := json.Marshal(wf)

	//base.Logf("Saving Workflow Def ...%s",wf)
	_, err = h.db.PutDocRaw(flowDefKey, data)
	//base.Logf("Done save...")

	if err != nil {
		return base.HTTPErrorf(http.StatusBadRequest, "Flow Definition Could not be updated") //TO DO: Need to relook at error
	}
	_, err = h.db.PutDocRaw(wf.Name, []byte(flowDefKey))

	// this should be inside db trx TO DO
	//_, err =writeLastVersion(h.db , wf.Name , )

	//db.Body{"ok": true, "flowDefKey": flowDefKey}
	h.writeJSONStatus(http.StatusCreated, &wf)
	return nil
}
Example #2
0
// HTTP handler for Flow query
func (h *handler) handleGetFlowDef() error {
	// derive flow def key from  URL path
	flowDefKey := h.PathVar("flowDefKey")
	base.Logf("Flow Definition Key: ", flowDefKey)

	if flowDefKey == "" {
		return base.HTTPErrorf(http.StatusBadRequest,
			"Invalid Flow Def Key")
	}

	data, err := h.db.GetDocRaw(flowDefKey)
	if err != nil {
		return base.HTTPErrorf(http.StatusBadRequest,
			"WF Definition Query Failed")
	}

	if data == nil {
		return base.HTTPErrorf(http.StatusBadRequest,
			"WF Definition Not Found. Check Flow Def Key again.")
	}

	wf := db.NewWorkflowDef(flowDefKey)

	err = json.Unmarshal([]byte(data), &wf)

	if err != nil {
		return err
	}

	h.writeJSONStatus(http.StatusCreated, wf)
	return nil
}
Example #3
0
// HTTP handler for Flow creation
//TO DO: Need to handle validations. Last Version write for deriving correct Def Keys on update.
// need to remove flow def from URL
func (h *handler) handlePostFlowDef() error {

	// derive flow name from URL path
	flowDefName := h.PathVar("flowName")
	base.Logf("...Flow Definition Name...", flowDefName)

	//generate flow def key
	flowDefKey, err := NextFlowDefKey(h.db, flowDefName)
	base.Logf("Flow Def Key:%s", flowDefKey)

	if flowDefKey == "" {
		return base.HTTPErrorf(http.StatusBadRequest, "Could not generate Flow Def Key")
	}

	wf := db.NewWorkflowDef(flowDefKey)

	_, err = h.readObject(wf)
	if err != nil {
		return base.HTTPErrorf(http.StatusBadRequest, "Could not map JSON to WfDef Object") //TO DO: Need to relook at error
	}

	//base.Logf("Encoding Workflow Def ..%s",wf)
	data, _ := json.Marshal(wf)

	//base.Logf("Saving Workflow Def ...%s",wf)
	_, _ = h.db.PutDocRaw(flowDefKey, data)
	//base.Logf("Done save...")

	// this should be inside db trx TO DO
	//_, err =writeLastVersion(h.db , wf.Name , )

	h.writeJSONStatus(http.StatusCreated, db.Body{"ok": true, "flowDefKey": flowDefKey})
	return nil
}
Example #4
0
func (h *handler) handlePostFlowTxn() error {

	base.Logf("handlePostFlowTxn...")

	flowInstanceReq := db.NewFlowTxnRequest()

	_, err := h.readObject(flowInstanceReq) //read JSON request into ftr object
	base.Logf("Read Object...")

	if err != nil {
		return base.HTTPErrorf(http.StatusBadRequest, "Could not map JSON to FlowTxnRequest Object")
	}

	base.Logf("Flow Def Key is", flowInstanceReq.FlowDefKey)

	//use flow def key to retrive workflow raw data and convert it to wf object
	flowDefData, _ := h.db.GetDocRaw(flowInstanceReq.FlowDefKey)
	flowDef := &db.WorkflowDef{}
	_ = json.Unmarshal(flowDefData, flowDef)

	flowInstance := db.NewFlowInstance(flowInstanceReq, flowDef)
	base.Logf("Flow Instance Key:%s", flowInstance.InstanceKey)

	// Save Flow Instance to database
	data, _ := json.Marshal(flowInstance)
	_, _ = h.db.PutDocRaw(flowInstance.InstanceKey, data)

	//JSON output created flow instance
	h.writeJSONStatus(http.StatusCreated, &flowInstance)
	return nil
}
Example #5
0
//general validation of DB name.
// can be skipped / changed according to database
func ValidateDatabaseName(dbName string) error {
	if match, _ := regexp.MatchString(`^[a-z][-a-z0-9_$()+/]*$`, dbName); !match {
		return base.HTTPErrorf(http.StatusBadRequest,
			"Illegal database name: %s", dbName)
	}
	return nil
}
Example #6
0
func (h *handler) writeMultipart(subtype string, callback func(*multipart.Writer) error) error {
	if !h.requestAccepts("multipart/") {
		return base.HTTPErrorf(http.StatusNotAcceptable, "Response is multipart")
	}

	// Get the output stream. Due to a CouchDB bug, if we're sending to it we need to buffer the
	// output in memory so we can trim the final bytes.
	var output io.Writer
	var buffer bytes.Buffer
	if h.userAgentIs("CouchDB") {
		output = &buffer
	} else {
		output = h.response
	}

	writer := multipart.NewWriter(output)
	h.setHeader("Content-Type",
		fmt.Sprintf("multipart/%s; boundary=%q", subtype, writer.Boundary()))

	err := callback(writer)
	writer.Close()

	if err == nil && output == &buffer {
		// Trim trailing newline; CouchDB is allergic to it:
		_, err = h.response.Write(bytes.TrimRight(buffer.Bytes(), "\r\n"))
	}
	return err
}
Example #7
0
// Reads & parses the request body, handling either JSON or multipart.
func (h *handler) readDocument() (db.Body, error) {
	//!contentType,  attrs, _ := mime.ParseMediaType(h.rq.Header.Get("Content-Type"))
	contentType, _, _ := mime.ParseMediaType(h.rq.Header.Get("Content-Type"))
	switch contentType {
	case "", "application/json":
		return h.readJSON()
	//case "multipart/related":
	//	if DebugMultipart {
	//		raw, err := h.readBody()
	//		if err != nil {
	//			return nil, err
	//		}
	//		reader := multipart.NewReader(bytes.NewReader(raw), attrs["boundary"])
	//		body, err := db.ReadMultipartDocument(reader)
	//		if err != nil {
	//			ioutil.WriteFile("GatewayPUT.mime", raw, 0600)
	//			base.Warn("Error reading MIME data: copied to file GatewayPUT.mime")
	//		}
	//		return body, err
	//	} else {
	//		reader := multipart.NewReader(h.requestBody, attrs["boundary"])
	//		return db.ReadMultipartDocument(reader)
	//	}
	default:
		return nil, base.HTTPErrorf(http.StatusUnsupportedMediaType, "Invalid content type %s", contentType)
	}
}
Example #8
0
// Parses a JSON request body into a custom structure.
func (h *handler) readJSONInto(into interface{}) error {

	contentType := h.rq.Header.Get("Content-Type")
	if contentType != "" && !strings.HasPrefix(contentType, "application/json") {
		return base.HTTPErrorf(http.StatusUnsupportedMediaType, "Invalid content type %s", contentType)
	}

	//TO DO: zip version to be added

	decoder := json.NewDecoder(h.requestBody)
	if err := decoder.Decode(into); err != nil {
		base.Warn("Couldn't parse JSON in HTTP request: %v", err)
		return base.HTTPErrorf(http.StatusBadRequest, "Bad JSON")
	}

	return nil
}
Example #9
0
// open new database connection handle
func OpenDatabase(spec base.DatabaseSpec) (dbhandle base.DbHandle, err error) {

	dbhandle, err = base.GetDbHandle(spec)

	if err != nil {
		err = base.HTTPErrorf(http.StatusBadGateway,
			"Unable to connect to server: %s", err)
	}

	return
}
Example #10
0
// HTTP handler for Flow query
func (h *handler) handleGetByNameFlowDef() error {
	// derive flow def key from  URL path
	flowDef := h.PathVar("flowDef")
	base.Logf("Flow Definition: ", flowDef)

	if flowDef == "" {
		return base.HTTPErrorf(http.StatusBadRequest,
			"Invalid Flow Def Name")
	}
	// get all flow def versions

	data, err := h.db.GetDocRaw(flowDef)
	if err != nil {
		return base.HTTPErrorf(http.StatusBadRequest,
			"WF Definition Query Failed")
	}

	base.Logf("Flow Def Key:%s", string(data))

	h.writeJSONStatus(http.StatusCreated, nil)
	return nil
}
Example #11
0
//TO DO: Need to add multi part reads
//This function handles marshaling of input JSON into Struct
func (h *handler) readObject(obj interface{}) (interface{}, error) {

	contentType, _, _ := mime.ParseMediaType(h.rq.Header.Get("Content-Type"))

	//process JSON Documents only
	switch contentType {

	case "", "application/json":
		return obj, h.readJSONInto(obj)
	default:
		return nil, base.HTTPErrorf(http.StatusUnsupportedMediaType, "Invalid content type %s", contentType)
	}
}
Example #12
0
func (sc *ServerContext) GetDatabase() (*db.DatabaseContext, error) {
	sc.lock.RLock()
	dbc := sc.database_
	sc.lock.RUnlock()

	if dbc != nil {
		return dbc, nil
	} else {
		return nil, base.HTTPErrorf(http.StatusBadRequest, "database name is invalid or it is not open ")
	}

	return dbc, nil
}
Example #13
0
// Top-level handler call. It's passed a pointer to the specific method to run.
func (h *handler) invoke(method handlerMethod) error {

	restExpvars.Add("requests_total", 1)
	restExpvars.Add("requests_active", 1)
	defer restExpvars.Add("requests_active", -1)

	switch h.rq.Header.Get("Content-Encoding") {
	case "":
		h.requestBody = h.rq.Body
	default:
		return base.HTTPErrorf(http.StatusUnsupportedMediaType, "Unsupported Content-Encoding;")
	}

	var err error

	// If there is a "db" path variable, look up the database context:
	var dbContext *db.DatabaseContext
	if dbContext, err = h.server.GetDatabase(); err != nil {
		h.logRequestLine()
		return err
	}

	// Authenticate, if not on admin port:
	//TO DO: Add authorization for DB Context
	//if h.privs != adminPrivs {
	//	if err = h.checkAuth(dbContext); err != nil {
	//		h.logRequestLine()
	//		return err
	//	}
	//}

	h.logRequestLine()

	// Now set the request's Database (i.e. context + user)
	if dbContext != nil {
		h.db, err = db.GetDatabase(dbContext, nil)

		if err != nil {
			return err
		}
	}

	return method(h) // Call the actual handler code

}
Example #14
0
// Get Document TO DO: Need to see if this is needed
// need to check if DBC or Database
func (db *DatabaseContext) GetDoc(docid string) (*document, error) {
	key := realDocID(docid)
	if key == "" {
		return nil, base.HTTPErrorf(400, "Invalid doc ID")
	}
	dbExpvars.Add("document_gets", 1) // need to check this
	doc := newDocument(docid)

	//get data from store
	data, err := db.DbHandle.GetRaw(key)
	if err != nil {
		return nil, err
	}
	//unmarshal JSON into doc.body
	doc.UnmarshalJSON(data)

	if err != nil {
		return nil, err
	}
	return doc, nil
}
Example #15
0
	"net/http"
	"net/url"
	"os"
	"strconv"
	"strings"
	"sync/atomic"
	"time"

	"github.com/gorilla/mux"

	"github.com/mindhash/goFlow/auth"
	"github.com/mindhash/goFlow/base"
	"github.com/mindhash/goFlow/db"
)

var kNotFoundError = base.HTTPErrorf(http.StatusNotFound, "missing")
var kBadMethodError = base.HTTPErrorf(http.StatusMethodNotAllowed, "Method Not Allowed")
var kBadRequestError = base.HTTPErrorf(http.StatusMethodNotAllowed, "Bad Request")

var restExpvars = expvar.NewMap("goflow_rest")

// If set to true, JSON output will be pretty-printed.
var PrettyPrint bool = false

// If set to true, diagnostic data will be dumped if there's a problem with MIME multipart data
var DebugMultipart bool = false

var lastSerialNum uint64 = 0

func init() {
	DebugMultipart = (os.Getenv("GatewayDebugMultipart") != "")