Beispiel #1
0
// GET: /user
func (cr *UserController) ReadMany(cx *goweb.Context) {
	// Log Request and check for Auth
	LogRequest(cx.Request)
	u, err := AuthenticateRequest(cx.Request)
	if err != nil {
		if err.Error() == e.NoAuth || err.Error() == e.UnAuth {
			cx.RespondWithError(http.StatusUnauthorized)
			return
		} else {
			log.Error("Err@user_Read: " + err.Error())
			cx.RespondWithError(http.StatusInternalServerError)
			return
		}
	}
	if u.Admin {
		users := user.Users{}
		user.AdminGet(&users)
		if len(users) > 0 {
			cx.RespondWithData(users)
			return
		} else {
			cx.RespondWithNotFound()
			return
		}
	} else {
		cx.RespondWithError(http.StatusUnauthorized)
		return
	}
}
Beispiel #2
0
func PreAuthRequest(cx *goweb.Context) {
	LogRequest(cx.Request)
	id := cx.PathParams["id"]
	if p, err := store.LoadPreAuth(id); err != nil {
		if err.Error() == e.MongoDocNotFound {
			cx.RespondWithNotFound()
		} else {
			cx.RespondWithError(http.StatusInternalServerError)
			log.Error("err:@preAuth load: " + err.Error())
		}
		return
	} else {
		if node, err := store.LoadNodeUnauth(p.NodeId); err == nil {
			switch p.Type {
			case "download":
				filename := node.Id
				if fn, has := p.Options["filename"]; has {
					filename = fn
				}
				streamDownload(cx, node, filename)
				store.DeletePreAuth(id)
				return
			default:
				cx.RespondWithError(http.StatusInternalServerError)
			}
		} else {
			cx.RespondWithError(http.StatusInternalServerError)
			log.Error("err:@preAuth loadnode: " + err.Error())
		}
	}
	return
}
Beispiel #3
0
// GET: /job/{id}
func (cr *JobController) Read(id string, cx *goweb.Context) {
	LogRequest(cx.Request)

	// Load job by id
	job, err := core.LoadJob(id)
	if err != nil {
		if err.Error() == e.MongoDocNotFound {
			cx.RespondWithNotFound()
			return
		} else {
			// In theory the db connection could be lost between
			// checking user and load but seems unlikely.
			Log.Error("Err@job_Read:LoadJob: " + id + ":" + err.Error())
			cx.RespondWithErrorMessage("job not found:"+id, http.StatusBadRequest)
			return
		}
	}
	// Base case respond with job in json
	cx.RespondWithData(job)
	return
}
Beispiel #4
0
// GET: /user/{id}
func (cr *UserController) Read(id string, cx *goweb.Context) {
	// Log Request and check for Auth
	LogRequest(cx.Request)
	u, err := AuthenticateRequest(cx.Request)
	if err != nil {
		if err.Error() == e.NoAuth || err.Error() == e.UnAuth {
			cx.RespondWithError(http.StatusUnauthorized)
			return
		} else {
			log.Error("Err@user_Read: " + err.Error())
			cx.RespondWithError(http.StatusInternalServerError)
			return
		}
	}
	// Any user can access their own user info. Only admins can
	// access other's info
	if u.Uuid == id {
		cx.RespondWithData(u)
		return
	} else if u.Admin {
		nu, err := user.FindByUuid(id)
		if err != nil {
			if err.Error() == e.MongoDocNotFound {
				cx.RespondWithNotFound()
				return
			} else {
				log.Error("Err@user_Read:Admin: " + err.Error())
				cx.RespondWithError(http.StatusInternalServerError)
				return
			}
		}
		cx.RespondWithData(nu)
		return
	} else {
		// Not sure how we could end up here but its probably the
		// user's fault
		cx.RespondWithError(http.StatusBadRequest)
		return
	}
}
Beispiel #5
0
// DELETE: /node/{id}
func (cr *NodeController) Delete(id string, cx *goweb.Context) {
	LogRequest(cx.Request)
	u, err := AuthenticateRequest(cx.Request)
	if err != nil && err.Error() != e.NoAuth {
		handleAuthError(err, cx)
		return
	}
	if u == nil {
		cx.RespondWithErrorMessage(e.NoAuth, http.StatusUnauthorized)
		return
	}

	// Load node and handle user unauthorized
	node, err := store.LoadNode(id, u.Uuid)
	if err != nil {
		if err.Error() == e.UnAuth {
			cx.RespondWithError(http.StatusUnauthorized)
			return
		} else if err.Error() == e.MongoDocNotFound {
			cx.RespondWithNotFound()
			return
		} else {
			// In theory the db connection could be lost between
			// checking user and load but seems unlikely.
			log.Error("Err@node_Read:Delete: " + err.Error())
			cx.RespondWithError(http.StatusInternalServerError)
			return
		}
	}

	if err := node.Delete(); err == nil {
		cx.RespondWithOK()
		return
	} else {
		log.Error("Err@node_Delet:Delete: " + err.Error())
		cx.RespondWithError(http.StatusInternalServerError)
	}
	return
}
Beispiel #6
0
// PUT: /node/{id} -> multipart-form
func (cr *NodeController) Update(id string, cx *goweb.Context) {
	// Log Request and check for Auth
	LogRequest(cx.Request)
	u, err := AuthenticateRequest(cx.Request)
	if err != nil && err.Error() != e.NoAuth {
		handleAuthError(err, cx)
		return
	}

	// Gather query params
	query := &Query{list: cx.Request.URL.Query()}

	// Fake public user
	if u == nil {
		u = &user.User{Uuid: ""}
	}

	node, err := store.LoadNode(id, u.Uuid)
	if err != nil {
		if err.Error() == e.UnAuth {
			cx.RespondWithError(http.StatusUnauthorized)
			return
		} else if err.Error() == e.MongoDocNotFound {
			cx.RespondWithNotFound()
			return
		} else {
			// In theory the db connection could be lost between
			// checking user and load but seems unlikely.
			log.Error("Err@node_Update:LoadNode: " + err.Error())
			cx.RespondWithError(http.StatusInternalServerError)
			return
		}
	}

	if query.Has("index") {
		if !node.HasFile() {
			cx.RespondWithErrorMessage("node file empty", http.StatusBadRequest)
			return
		}

		if query.Value("index") == "bai" {

			//bam index is created by the command-line tool samtools
			if ext := node.FileExt(); ext == ".bam" {
				if err := CreateBamIndex(node.FilePath()); err != nil {
					cx.RespondWithErrorMessage("Error while creating bam index", http.StatusBadRequest)
					return
				}
				return
			} else {
				cx.RespondWithErrorMessage("Index type bai requires .bam file", http.StatusBadRequest)
				return
			}
		}

		newIndexer := indexer.Indexer(query.Value("index"))
		f, _ := os.Open(node.FilePath())
		defer f.Close()
		idxer := newIndexer(f)
		err := idxer.Create()
		if err != nil {
			log.Error("err " + err.Error())
		}
		err = idxer.Dump(node.IndexPath() + "/record")
		if err != nil {
			cx.RespondWithErrorMessage(err.Error(), http.StatusBadRequest)
			return
		} else {
			cx.RespondWithOK()
			return
		}
	} else {
		params, files, err := ParseMultipartForm(cx.Request)
		if err != nil {
			log.Error("err " + err.Error())
			cx.RespondWithError(http.StatusBadRequest)
			return
		}

		err = node.Update(params, files)
		if err != nil {
			errors := []string{e.FileImut, e.AttrImut, "parts cannot be less than 1"}
			for e := range errors {
				if err.Error() == errors[e] {
					cx.RespondWithErrorMessage(err.Error(), http.StatusBadRequest)
					return
				}
			}
			log.Error("err " + err.Error())
			cx.RespondWithErrorMessage(err.Error(), http.StatusBadRequest)
			return
		}
		cx.RespondWithData(node)
	}
	return
}
Beispiel #7
0
// GET: /node/{id}
// ToDo: clean up this function. About to get unmanageable
func (cr *NodeController) Read(id string, cx *goweb.Context) {
	// Log Request and check for Auth
	LogRequest(cx.Request)
	u, err := AuthenticateRequest(cx.Request)
	if err != nil && err.Error() != e.NoAuth {
		handleAuthError(err, cx)
		return
	}

	// Fake public user
	if u == nil {
		if conf.ANON_READ {
			u = &user.User{Uuid: ""}
		} else {
			cx.RespondWithErrorMessage(e.NoAuth, http.StatusUnauthorized)
			return
		}
	}

	// Gather query params
	query := &Query{list: cx.Request.URL.Query()}

	var fFunc filter.FilterFunc = nil
	if query.Has("filter") {
		if filter.Has(query.Value("filter")) {
			fFunc = filter.Filter(query.Value("filter"))
		}
	}

	// Load node and handle user unauthorized
	node, err := store.LoadNode(id, u.Uuid)
	if err != nil {
		if err.Error() == e.UnAuth {
			cx.RespondWithError(http.StatusUnauthorized)
			return
		} else if err.Error() == e.MongoDocNotFound {
			cx.RespondWithNotFound()
			return
		} else {
			// In theory the db connection could be lost between
			// checking user and load but seems unlikely.
			log.Error("Err@node_Read:LoadNode: " + err.Error())
			cx.RespondWithError(http.StatusInternalServerError)
			return
		}
	}

	// Switch though param flags
	// ?download=1
	if query.Has("download") {
		if !node.HasFile() {
			cx.RespondWithErrorMessage("File not found", http.StatusBadRequest)
			return
		}

		//_, chunksize :=
		// ?index=foo
		if query.Has("index") {
			//handling bam file
			if query.Value("index") == "bai" {
				s := &streamer{rs: []store.SectionReader{}, ws: cx.ResponseWriter, contentType: "application/octet-stream", filename: node.Id, size: node.File.Size, filter: fFunc}

				var region string

				if query.Has("region") {
					//retrieve alingments overlapped with specified region
					region = query.Value("region")
				}

				argv, err := ParseSamtoolsArgs(query)
				if err != nil {
					cx.RespondWithErrorMessage("Invaid args in query url", http.StatusBadRequest)
					return
				}

				err = s.stream_samtools(node.FilePath(), region, argv...)
				if err != nil {
					cx.RespondWithErrorMessage("error while involking samtools", http.StatusBadRequest)
					return
				}

				return
			}

			// if forgot ?part=N
			if !query.Has("part") {
				cx.RespondWithErrorMessage("Index parameter requires part parameter", http.StatusBadRequest)
				return
			}
			// open file
			r, err := node.FileReader()
			if err != nil {
				log.Error("Err@node_Read:Open: " + err.Error())
				cx.RespondWithError(http.StatusInternalServerError)
				return
			}
			// load index
			idx, err := node.Index(query.Value("index"))
			if err != nil {
				cx.RespondWithErrorMessage("Invalid index", http.StatusBadRequest)
				return
			}

			if idx.Type() == "virtual" {
				csize := int64(1048576)
				if query.Has("chunksize") {
					csize, err = strconv.ParseInt(query.Value("chunksize"), 10, 64)
					if err != nil {
						cx.RespondWithErrorMessage("Invalid chunksize", http.StatusBadRequest)
						return
					}
				}
				idx.Set(map[string]interface{}{"ChunkSize": csize})
			}
			var size int64 = 0
			s := &streamer{rs: []store.SectionReader{}, ws: cx.ResponseWriter, contentType: "application/octet-stream", filename: node.Id, filter: fFunc}
			for _, p := range query.List("part") {
				pos, length, err := idx.Part(p)
				if err != nil {
					cx.RespondWithErrorMessage("Invalid index part", http.StatusBadRequest)
					return
				}
				size += length
				s.rs = append(s.rs, io.NewSectionReader(r, pos, length))
			}
			s.size = size
			err = s.stream()
			if err != nil {
				// causes "multiple response.WriteHeader calls" error but better than no response
				cx.RespondWithErrorMessage(err.Error(), http.StatusBadRequest)
				log.Error("err: " + err.Error())
			}
		} else { //!query.Has("index")
			nf, err := node.FileReader()
			if err != nil {
				// File not found or some sort of file read error.
				// Probably deserves more checking
				log.Error("err " + err.Error())
				cx.RespondWithError(http.StatusBadRequest)
				return
			}
			s := &streamer{rs: []store.SectionReader{nf}, ws: cx.ResponseWriter, contentType: "application/octet-stream", filename: node.Id, size: node.File.Size, filter: fFunc}
			err = s.stream()
			if err != nil {
				// causes "multiple response.WriteHeader calls" error but better than no response
				cx.RespondWithErrorMessage(err.Error(), http.StatusBadRequest)
				log.Error("err " + err.Error())
			}
		}
		return
	} else if query.Has("pipe") {
		cx.RespondWithError(http.StatusNotImplemented)
	} else if query.Has("list") {
		cx.RespondWithError(http.StatusNotImplemented)
	} else {
		// Base case respond with node in json
		cx.RespondWithData(node)
	}
}
Beispiel #8
0
// PUT: /node/{id} -> multipart-form
func (cr *NodeController) Update(id string, cx *goweb.Context) {
	// Log Request and check for Auth
	LogRequest(cx.Request)
	u, err := AuthenticateRequest(cx.Request)
	if err != nil && err.Error() != e.NoAuth {
		handleAuthError(err, cx)
		return
	}

	// Gather query params
	query := &Query{list: cx.Request.URL.Query()}

	// Fake public user
	if u == nil {
		u = &user.User{Uuid: ""}
	}

	node, err := store.LoadNode(id, u.Uuid)
	if err != nil {
		if err.Error() == e.UnAuth {
			cx.RespondWithError(http.StatusUnauthorized)
			return
		} else if err.Error() == e.MongoDocNotFound {
			cx.RespondWithNotFound()
			return
		} else {
			// In theory the db connection could be lost between
			// checking user and load but seems unlikely.
			log.Error("Err@node_Update:LoadNode: " + err.Error())
			cx.RespondWithError(http.StatusInternalServerError)
			return
		}
	}

	if query.Has("index") {
		if conf.PERF_LOG {
			log.Perf("START indexing: " + id)
		}

		if !node.HasFile() {
			cx.RespondWithErrorMessage("node file empty", http.StatusBadRequest)
			return
		}

		if query.Value("index") == "bai" {
			//bam index is created by the command-line tool samtools
			if ext := node.FileExt(); ext == ".bam" {
				if err := CreateBamIndex(node.FilePath()); err != nil {
					cx.RespondWithErrorMessage("Error while creating bam index", http.StatusBadRequest)
					return
				}
				return
			} else {
				cx.RespondWithErrorMessage("Index type bai requires .bam file", http.StatusBadRequest)
				return
			}
		}

		idxtype := query.Value("index")
		if _, ok := indexer.Indexers[idxtype]; !ok {
			cx.RespondWithErrorMessage("invalid index type", http.StatusBadRequest)
			return
		}

		newIndexer := indexer.Indexer(idxtype)
		f, _ := os.Open(node.FilePath())
		defer f.Close()
		idxer := newIndexer(f)
		count, err := idxer.Create()
		if err != nil {
			log.Error("err " + err.Error())
			cx.RespondWithErrorMessage(err.Error(), http.StatusBadRequest)
			return
		}

		if err := idxer.Dump(node.IndexPath() + "/" + query.Value("index") + ".idx"); err != nil {
			log.Error("err " + err.Error())
			cx.RespondWithErrorMessage(err.Error(), http.StatusBadRequest)
			return
		}

		idxInfo := store.IdxInfo{
			Type:        query.Value("index"),
			TotalUnits:  count,
			AvgUnitSize: node.File.Size / count,
		}

		if idxtype == "chunkrecord" {
			idxInfo.AvgUnitSize = conf.CHUNK_SIZE
		}

		if err := node.SetIndexInfo(query.Value("index"), idxInfo); err != nil {
			log.Error("[email protected]: " + err.Error())
		}

		if conf.PERF_LOG {
			log.Perf("END indexing: " + id)
		}

		cx.RespondWithOK()
		return

	} else {
		if conf.PERF_LOG {
			log.Perf("START PUT data: " + id)
		}
		params, files, err := ParseMultipartForm(cx.Request)
		if err != nil {
			log.Error("err@node_ParseMultipartForm: " + err.Error())
			cx.RespondWithError(http.StatusBadRequest)
			return
		}

		err = node.Update(params, files)
		if err != nil {
			errors := []string{e.FileImut, e.AttrImut, "parts cannot be less than 1"}
			for e := range errors {
				if err.Error() == errors[e] {
					cx.RespondWithErrorMessage(err.Error(), http.StatusBadRequest)
					return
				}
			}
			log.Error("err@node_Update: " + id + ":" + err.Error())
			cx.RespondWithErrorMessage(err.Error(), http.StatusBadRequest)
			return
		}
		cx.RespondWithData(node)
		if conf.PERF_LOG {
			log.Perf("END PUT data: " + id)
		}
	}
	return
}