Ejemplo n.º 1
0
// Get loads the document with the given ID into dst.
//
// The ID is a human-readable ASCII string. It must be non-empty, contain no
// whitespace characters and not start with "!".
//
// dst must be a non-nil struct pointer or implement the FieldLoadSaver
// interface.
//
// ErrFieldMismatch is returned when a field is to be loaded into a different
// type than the one it was stored from, or when a field is missing or
// unexported in the destination struct. ErrFieldMismatch is only returned if
// dst is a struct pointer. It is up to the callee to decide whether this error
// is fatal, recoverable, or ignorable.
func (x *Index) Get(c appengine.Context, id string, dst interface{}) error {
	if id == "" || !validIndexNameOrDocID(id) {
		return fmt.Errorf("search: invalid ID %q", id)
	}
	req := &pb.ListDocumentsRequest{
		Params: &pb.ListDocumentsParams{
			IndexSpec:  &x.spec,
			StartDocId: proto.String(id),
			Limit:      proto.Int32(1),
		},
	}
	res := &pb.ListDocumentsResponse{}
	if err := c.Call("search", "ListDocuments", req, res, nil); err != nil {
		return err
	}
	if res.Status == nil || res.Status.GetCode() != pb.SearchServiceError_OK {
		return fmt.Errorf("search: %s: %s", res.Status.GetCode(), res.Status.GetErrorDetail())
	}
	if len(res.Document) != 1 || res.Document[0].GetId() != id {
		return ErrNoSuchDocument
	}
	metadata := &DocumentMetadata{
		Rank: int(res.Document[0].GetOrderId()),
	}
	return loadDoc(dst, res.Document[0].Field, nil, metadata)
}
Ejemplo n.º 2
0
// DeleteMulti deletes multiple tasks from a named queue.
// If a given task could not be deleted, an appengine.MultiError is returned.
func DeleteMulti(c appengine.Context, tasks []*Task, queueName string) error {
	taskNames := make([][]byte, len(tasks))
	for i, t := range tasks {
		taskNames[i] = []byte(t.Name)
	}
	if queueName == "" {
		queueName = "default"
	}
	req := &pb.TaskQueueDeleteRequest{
		QueueName: []byte(queueName),
		TaskName:  taskNames,
	}
	res := &pb.TaskQueueDeleteResponse{}
	if err := c.Call("taskqueue", "Delete", req, res, nil); err != nil {
		return err
	}
	if a, b := len(req.TaskName), len(res.Result); a != b {
		return fmt.Errorf("taskqueue: internal error: requested deletion of %d tasks, got %d results", a, b)
	}
	me, any := make(appengine.MultiError, len(res.Result)), false
	for i, ec := range res.Result {
		if ec != pb.TaskQueueServiceError_OK {
			me[i] = &internal.APIError{
				Service: "taskqueue",
				Code:    int32(ec),
			}
			any = true
		}
	}
	if any {
		return me
	}
	return nil
}
Ejemplo n.º 3
0
// Send sends a message.
// If any failures occur with specific recipients, the error will be an appengine.MultiError.
func (m *Message) Send(c appengine.Context) error {
	req := &pb.XmppMessageRequest{
		Jid:    m.To,
		Body:   &m.Body,
		RawXml: &m.RawXML,
	}
	if m.Type != "" && m.Type != "chat" {
		req.Type = &m.Type
	}
	if m.Sender != "" {
		req.FromJid = &m.Sender
	}
	res := &pb.XmppMessageResponse{}
	if err := c.Call("xmpp", "SendMessage", req, res, nil); err != nil {
		return err
	}

	if len(res.Status) != len(req.Jid) {
		return fmt.Errorf("xmpp: sent message to %d JIDs, but only got %d statuses back", len(req.Jid), len(res.Status))
	}
	me, any := make(appengine.MultiError, len(req.Jid)), false
	for i, st := range res.Status {
		if st != pb.XmppMessageResponse_NO_ERROR {
			me[i] = errors.New(st.String())
			any = true
		}
	}
	if any {
		return me
	}
	return nil
}
Ejemplo n.º 4
0
func lease(c appengine.Context, maxTasks int, queueName string, leaseTime int, groupByTag bool, tag []byte) ([]*Task, error) {
	if queueName == "" {
		queueName = "default"
	}
	req := &pb.TaskQueueQueryAndOwnTasksRequest{
		QueueName:    []byte(queueName),
		LeaseSeconds: proto.Float64(float64(leaseTime)),
		MaxTasks:     proto.Int64(int64(maxTasks)),
		GroupByTag:   proto.Bool(groupByTag),
		Tag:          tag,
	}
	res := &pb.TaskQueueQueryAndOwnTasksResponse{}
	callOpts := &internal.CallOptions{
		Timeout: 10 * time.Second,
	}
	if err := c.Call("taskqueue", "QueryAndOwnTasks", req, res, callOpts); err != nil {
		return nil, err
	}
	tasks := make([]*Task, len(res.Task))
	for i, t := range res.Task {
		tasks[i] = &Task{
			Payload:    t.Body,
			Name:       string(t.TaskName),
			Method:     "PULL",
			ETA:        time.Unix(0, *t.EtaUsec*1e3),
			RetryCount: *t.RetryCount,
			Tag:        string(t.Tag),
		}
	}
	return tasks, nil
}
Ejemplo n.º 5
0
// AllocateIDs returns a range of n integer IDs with the given kind and parent
// combination. kind cannot be empty; parent may be nil. The IDs in the range
// returned will not be used by the datastore's automatic ID sequence generator
// and may be used with NewKey without conflict.
//
// The range is inclusive at the low end and exclusive at the high end. In
// other words, valid intIDs x satisfy low <= x && x < high.
//
// If no error is returned, low + n == high.
func AllocateIDs(c appengine.Context, kind string, parent *Key, n int) (low, high int64, err error) {
	if kind == "" {
		return 0, 0, errors.New("datastore: AllocateIDs given an empty kind")
	}
	if n < 0 {
		return 0, 0, fmt.Errorf("datastore: AllocateIDs given a negative count: %d", n)
	}
	if n == 0 {
		return 0, 0, nil
	}
	req := &pb.AllocateIdsRequest{
		ModelKey: keyToProto("", NewIncompleteKey(c, kind, parent)),
		Size:     proto.Int64(int64(n)),
	}
	res := &pb.AllocateIdsResponse{}
	if err := c.Call("datastore_v3", "AllocateIds", req, res, nil); err != nil {
		return 0, 0, err
	}
	// The protobuf is inclusive at both ends. Idiomatic Go (e.g. slices, for loops)
	// is inclusive at the low end and exclusive at the high end, so we add 1.
	low = res.GetStart()
	high = res.GetEnd() + 1
	if low+int64(n) != high {
		return 0, 0, fmt.Errorf("datastore: internal error: could not allocate %d IDs", n)
	}
	return low, high, nil
}
Ejemplo n.º 6
0
// QueueStats retrieves statistics about queues.
func QueueStats(c appengine.Context, queueNames []string) ([]QueueStatistics, error) {
	req := &pb.TaskQueueFetchQueueStatsRequest{
		QueueName: make([][]byte, len(queueNames)),
	}
	for i, q := range queueNames {
		if q == "" {
			q = "default"
		}
		req.QueueName[i] = []byte(q)
	}
	res := &pb.TaskQueueFetchQueueStatsResponse{}
	callOpts := &internal.CallOptions{
		Timeout: 10 * time.Second,
	}
	if err := c.Call("taskqueue", "FetchQueueStats", req, res, callOpts); err != nil {
		return nil, err
	}
	qs := make([]QueueStatistics, len(res.Queuestats))
	for i, qsg := range res.Queuestats {
		qs[i] = QueueStatistics{
			Tasks: int(*qsg.NumTasks),
		}
		if eta := *qsg.OldestEtaUsec; eta > -1 {
			qs[i].OldestETA = time.Unix(0, eta*1e3)
		}
		if si := qsg.ScannerInfo; si != nil {
			qs[i].Executed1Minute = int(*si.ExecutedLastMinute)
			qs[i].InFlight = int(si.GetRequestsInFlight())
			qs[i].EnforcedRate = si.GetEnforcedRate()
		}
	}
	return qs, nil
}
Ejemplo n.º 7
0
// DeleteMulti is a batch version of Delete.
// If any keys cannot be found, an appengine.MultiError is returned.
// Each key must be at most 250 bytes in length.
func DeleteMulti(c appengine.Context, key []string) error {
	req := &pb.MemcacheDeleteRequest{
		Item: make([]*pb.MemcacheDeleteRequest_Item, len(key)),
	}
	for i, k := range key {
		req.Item[i] = &pb.MemcacheDeleteRequest_Item{Key: []byte(k)}
	}
	res := &pb.MemcacheDeleteResponse{}
	if err := c.Call("memcache", "Delete", req, res, nil); err != nil {
		return err
	}
	if len(res.DeleteStatus) != len(key) {
		return ErrServerError
	}
	me, any := make(appengine.MultiError, len(key)), false
	for i, s := range res.DeleteStatus {
		switch s {
		case pb.MemcacheDeleteResponse_DELETED:
			// OK
		case pb.MemcacheDeleteResponse_NOT_FOUND:
			me[i] = ErrCacheMiss
			any = true
		default:
			me[i] = ErrServerError
			any = true
		}
	}
	if any {
		return me
	}
	return nil
}
Ejemplo n.º 8
0
// Put saves src to the index. If id is empty, a new ID is allocated by the
// service and returned. If id is not empty, any existing index entry for that
// ID is replaced.
//
// The ID is a human-readable ASCII string. It must contain no whitespace
// characters and not start with "!".
//
// src must be a non-nil struct pointer.
func (x *Index) Put(c appengine.Context, id string, src interface{}) (string, error) {
	fields, err := saveFields(src)
	if err != nil {
		return "", err
	}
	d := &pb.Document{
		Field: fields,
	}
	if id != "" {
		if !validIndexNameOrDocID(id) {
			return "", fmt.Errorf("search: invalid ID %q", id)
		}
		d.Id = proto.String(id)
	}
	req := &pb.IndexDocumentRequest{
		Params: &pb.IndexDocumentParams{
			Document:  []*pb.Document{d},
			IndexSpec: &x.spec,
		},
	}
	res := &pb.IndexDocumentResponse{}
	if err := c.Call("search", "IndexDocument", req, res, nil); err != nil {
		return "", err
	}
	if len(res.Status) != 1 || len(res.DocId) != 1 {
		return "", fmt.Errorf("search: internal error: wrong number of results (%d Statuses, %d DocIDs)",
			len(res.Status), len(res.DocId))
	}
	if s := res.Status[0]; s.GetCode() != pb.SearchServiceError_OK {
		return "", fmt.Errorf("search: %s: %s", s.GetCode(), s.GetErrorDetail())
	}
	return res.DocId[0], nil
}
Ejemplo n.º 9
0
// DeleteServingURL deletes the serving URL for an image.
func DeleteServingURL(c appengine.Context, key appengine.BlobKey) error {
	req := &pb.ImagesDeleteUrlBaseRequest{
		BlobKey: (*string)(&key),
	}
	res := &pb.ImagesDeleteUrlBaseResponse{}
	return c.Call("images", "DeleteUrlBase", req, res, nil)
}
Ejemplo n.º 10
0
// Send sends a message on the channel associated with clientID.
func Send(c appengine.Context, clientID, message string) error {
	req := &pb.SendMessageRequest{
		ApplicationKey: &clientID,
		Message:        &message,
	}
	resp := &basepb.VoidProto{}
	return remapError(c.Call(service, "SendChannelMessage", req, resp, nil))
}
Ejemplo n.º 11
0
// Create creates a channel and returns a token for use by the client.
// The clientID is an application-provided string used to identify the client.
func Create(c appengine.Context, clientID string) (token string, err error) {
	req := &pb.CreateChannelRequest{
		ApplicationKey: &clientID,
	}
	resp := &pb.CreateChannelResponse{}
	err = c.Call(service, "CreateChannel", req, resp, nil)
	token = resp.GetToken()
	return token, remapError(err)
}
Ejemplo n.º 12
0
// DefaultVersion returns the default version of the specified module.
// If module is the empty string, it means the default module.
func DefaultVersion(c appengine.Context, module string) (string, error) {
	req := &pb.GetDefaultVersionRequest{}
	if module != "" {
		req.Module = &module
	}
	res := &pb.GetDefaultVersionResponse{}
	err := c.Call("modules", "GetDefaultVersion", req, res, nil)
	return res.GetVersion(), err
}
Ejemplo n.º 13
0
// DefaultBucketName returns the name of this application's
// default Google Cloud Storage bucket.
func DefaultBucketName(c appengine.Context) (string, error) {
	req := &aipb.GetDefaultGcsBucketNameRequest{}
	res := &aipb.GetDefaultGcsBucketNameResponse{}

	err := c.Call("app_identity_service", "GetDefaultGcsBucketName", req, res, nil)
	if err != nil {
		return "", fmt.Errorf("file: no default bucket name returned in RPC response: %v", res)
	}
	return res.GetDefaultGcsBucketName(), nil
}
Ejemplo n.º 14
0
// LogoutURL returns a URL that, when visited, signs the user out,
// then redirects the user to the URL specified by dest.
func LogoutURL(c appengine.Context, dest string) (string, error) {
	req := &pb.CreateLogoutURLRequest{
		DestinationUrl: proto.String(dest),
	}
	res := &pb.CreateLogoutURLResponse{}
	if err := c.Call("user", "CreateLogoutURL", req, res, nil); err != nil {
		return "", err
	}
	return *res.LogoutUrl, nil
}
Ejemplo n.º 15
0
// OAuthConsumerKey returns the OAuth consumer key provided with the current
// request. This method will return an error if the OAuth request was invalid.
func OAuthConsumerKey(c appengine.Context) (string, error) {
	req := &pb.CheckOAuthSignatureRequest{}
	res := &pb.CheckOAuthSignatureResponse{}

	err := c.Call("user", "CheckOAuthSignature", req, res, nil)
	if err != nil {
		return "", err
	}
	return *res.OauthConsumerKey, err
}
Ejemplo n.º 16
0
// Invite sends an invitation. If the from address is an empty string
// the default ([email protected]/bot) will be used.
func Invite(c appengine.Context, to, from string) error {
	req := &pb.XmppInviteRequest{
		Jid: &to,
	}
	if from != "" {
		req.FromJid = &from
	}
	res := &pb.XmppInviteResponse{}
	return c.Call("xmpp", "SendInvite", req, res, nil)
}
Ejemplo n.º 17
0
// Purge removes all tasks from a queue.
func Purge(c appengine.Context, queueName string) error {
	if queueName == "" {
		queueName = "default"
	}
	req := &pb.TaskQueuePurgeQueueRequest{
		QueueName: []byte(queueName),
	}
	res := &pb.TaskQueuePurgeQueueResponse{}
	return c.Call("taskqueue", "PurgeQueue", req, res, nil)
}
Ejemplo n.º 18
0
// Start starts the specified version of the specified module.
// If either module or version are the empty string, it means the default.
func Start(c appengine.Context, module, version string) error {
	req := &pb.StartModuleRequest{}
	if module != "" {
		req.Module = &module
	}
	if version != "" {
		req.Version = &version
	}
	res := &pb.StartModuleResponse{}
	return c.Call("modules", "StartModule", req, res, nil)
}
Ejemplo n.º 19
0
// SetNumInstances sets the number of instances of the given module.version to the
// specified value. If either module or version are the empty string it means the
// default.
func SetNumInstances(c appengine.Context, module, version string, instances int) error {
	req := &pb.SetNumInstancesRequest{}
	if module != "" {
		req.Module = &module
	}
	if version != "" {
		req.Version = &version
	}
	req.Instances = proto.Int64(int64(instances))
	res := &pb.SetNumInstancesResponse{}
	return c.Call("modules", "SetNumInstances", req, res, nil)
}
Ejemplo n.º 20
0
// LoginURLFederated is like LoginURL but accepts a user's OpenID identifier.
func LoginURLFederated(c appengine.Context, dest, identity string) (string, error) {
	req := &pb.CreateLoginURLRequest{
		DestinationUrl: proto.String(dest),
	}
	if identity != "" {
		req.FederatedIdentity = proto.String(identity)
	}
	res := &pb.CreateLoginURLResponse{}
	if err := c.Call("user", "CreateLoginURL", req, res, nil); err != nil {
		return "", err
	}
	return *res.LoginUrl, nil
}
Ejemplo n.º 21
0
// DeleteMulti is a batch version of Delete.
func DeleteMulti(c appengine.Context, key []*Key) error {
	if len(key) == 0 {
		return nil
	}
	if err := multiValid(key); err != nil {
		return err
	}
	req := &pb.DeleteRequest{
		Key: multiKeyToProto(c.FullyQualifiedAppID(), key),
	}
	res := &pb.DeleteResponse{}
	return c.Call("datastore_v3", "Delete", req, res, nil)
}
Ejemplo n.º 22
0
// NumInstances returns the number of instances of the given module/version.
// If either argument is the empty string it means the default.
func NumInstances(c appengine.Context, module, version string) (int, error) {
	req := &pb.GetNumInstancesRequest{}
	if module != "" {
		req.Module = &module
	}
	if version != "" {
		req.Version = &version
	}
	res := &pb.GetNumInstancesResponse{}

	if err := c.Call("modules", "GetNumInstances", req, res, nil); err != nil {
		return 0, err
	}
	return int(*res.Instances), nil
}
Ejemplo n.º 23
0
// GetMulti is a batch version of Get.
//
// dst must be a []S, []*S, []I or []P, for some struct type S, some interface
// type I, or some non-interface non-pointer type P such that P or *P
// implements PropertyLoadSaver. If an []I, each element must be a valid dst
// for Get: it must be a struct pointer or implement PropertyLoadSaver.
//
// As a special case, PropertyList is an invalid type for dst, even though a
// PropertyList is a slice of structs. It is treated as invalid to avoid being
// mistakenly passed when []PropertyList was intended.
func GetMulti(c appengine.Context, key []*Key, dst interface{}) error {
	v := reflect.ValueOf(dst)
	multiArgType, _ := checkMultiArg(v)
	if multiArgType == multiArgTypeInvalid {
		return errors.New("datastore: dst has invalid type")
	}
	if len(key) != v.Len() {
		return errors.New("datastore: key and dst slices have different length")
	}
	if len(key) == 0 {
		return nil
	}
	if err := multiValid(key); err != nil {
		return err
	}
	req := &pb.GetRequest{
		Key: multiKeyToProto(c.FullyQualifiedAppID(), key),
	}
	res := &pb.GetResponse{}
	if err := c.Call("datastore_v3", "Get", req, res, nil); err != nil {
		return err
	}
	if len(key) != len(res.Entity) {
		return errors.New("datastore: internal error: server returned the wrong number of entities")
	}
	multiErr, any := make(appengine.MultiError, len(key)), false
	for i, e := range res.Entity {
		if e.Entity == nil {
			multiErr[i] = ErrNoSuchEntity
		} else {
			elem := v.Index(i)
			if multiArgType == multiArgTypePropertyLoadSaver || multiArgType == multiArgTypeStruct {
				elem = elem.Addr()
			}
			if multiArgType == multiArgTypeStructPtr && elem.IsNil() {
				elem.Set(reflect.New(elem.Type().Elem()))
			}
			multiErr[i] = loadEntity(elem.Interface(), e.Entity)
		}
		if multiErr[i] != nil {
			any = true
		}
	}
	if any {
		return multiErr
	}
	return nil
}
Ejemplo n.º 24
0
func runOnce(c appengine.Context, f func(appengine.Context) error, opts *TransactionOptions) error {
	// Begin the transaction.
	t := &transaction{Context: c}
	req := &pb.BeginTransactionRequest{
		App: proto.String(c.FullyQualifiedAppID()),
	}
	if opts != nil && opts.XG {
		req.AllowMultipleEg = proto.Bool(true)
	}
	if err := t.Context.Call("datastore_v3", "BeginTransaction", req, &t.transaction, nil); err != nil {
		return err
	}

	// Call f, rolling back the transaction if f returns a non-nil error, or panics.
	// The panic is not recovered.
	defer func() {
		if t.finished {
			return
		}
		t.finished = true
		// Ignore the error return value, since we are already returning a non-nil
		// error (or we're panicking).
		c.Call("datastore_v3", "Rollback", &t.transaction, &basepb.VoidProto{}, nil)
	}()
	if err := f(t); err != nil {
		return err
	}
	t.finished = true

	// Commit the transaction.
	res := &pb.CommitResponse{}
	err := c.Call("datastore_v3", "Commit", &t.transaction, res, nil)
	if ae, ok := err.(*internal.APIError); ok {
		if appengine.IsDevAppServer() {
			// The Python Dev AppServer raises an ApplicationError with error code 2 (which is
			// Error.CONCURRENT_TRANSACTION) and message "Concurrency exception.".
			if ae.Code == int32(pb.Error_BAD_REQUEST) && ae.Detail == "ApplicationError: 2 Concurrency exception." {
				return ErrConcurrentTransaction
			}
		}
		if ae.Code == int32(pb.Error_CONCURRENT_TRANSACTION) {
			return ErrConcurrentTransaction
		}
	}
	return err
}
Ejemplo n.º 25
0
// ModifyLease modifies the lease of a task.
// Used to request more processing time, or to abandon processing.
// leaseTime is in seconds and must not be negative.
func ModifyLease(c appengine.Context, task *Task, queueName string, leaseTime int) error {
	if queueName == "" {
		queueName = "default"
	}
	req := &pb.TaskQueueModifyTaskLeaseRequest{
		QueueName:    []byte(queueName),
		TaskName:     []byte(task.Name),
		EtaUsec:      proto.Int64(task.ETA.UnixNano() / 1e3), // Used to verify ownership.
		LeaseSeconds: proto.Float64(float64(leaseTime)),
	}
	res := &pb.TaskQueueModifyTaskLeaseResponse{}
	if err := c.Call("taskqueue", "ModifyTaskLease", req, res, nil); err != nil {
		return err
	}
	task.ETA = time.Unix(0, *res.UpdatedEtaUsec*1e3)
	return nil
}
Ejemplo n.º 26
0
// GetPresenceMulti retrieves multiple users' presence.
// If the from address is an empty string the default
// ([email protected]/bot) will be used.
// Possible return values are "", "away", "dnd", "chat", "xa".
// If any presence is unavailable, an appengine.MultiError is returned
func GetPresenceMulti(c appengine.Context, to []string, from string) ([]string, error) {
	req := &pb.BulkPresenceRequest{
		Jid: to,
	}
	if from != "" {
		req.FromJid = &from
	}
	res := &pb.BulkPresenceResponse{}

	if err := c.Call("xmpp", "BulkGetPresence", req, res, nil); err != nil {
		return nil, err
	}

	presences := make([]string, 0, len(res.PresenceResponse))
	errs := appengine.MultiError{}

	addResult := func(presence string, err error) {
		presences = append(presences, presence)
		errs = append(errs, err)
	}

	anyErr := false
	for _, subres := range res.PresenceResponse {
		if !subres.GetValid() {
			anyErr = true
			addResult("", ErrInvalidJID)
			continue
		}
		if !*subres.IsAvailable || subres.Presence == nil {
			anyErr = true
			addResult("", ErrPresenceUnavailable)
			continue
		}
		presence, ok := presenceMap[*subres.Presence]
		if ok {
			addResult(presence, nil)
		} else {
			anyErr = true
			addResult("", fmt.Errorf("xmpp: unknown presence %q", *subres.Presence))
		}
	}
	if anyErr {
		return presences, errs
	}
	return presences, nil
}
Ejemplo n.º 27
0
// PutMulti is a batch version of Put.
//
// src must satisfy the same conditions as the dst argument to GetMulti.
func PutMulti(c appengine.Context, key []*Key, src interface{}) ([]*Key, error) {
	v := reflect.ValueOf(src)
	multiArgType, _ := checkMultiArg(v)
	if multiArgType == multiArgTypeInvalid {
		return nil, errors.New("datastore: src has invalid type")
	}
	if len(key) != v.Len() {
		return nil, errors.New("datastore: key and src slices have different length")
	}
	if len(key) == 0 {
		return nil, nil
	}
	appID := c.FullyQualifiedAppID()
	if err := multiValid(key); err != nil {
		return nil, err
	}
	req := &pb.PutRequest{}
	for i := range key {
		elem := v.Index(i)
		if multiArgType == multiArgTypePropertyLoadSaver || multiArgType == multiArgTypeStruct {
			elem = elem.Addr()
		}
		sProto, err := saveEntity(appID, key[i], elem.Interface())
		if err != nil {
			return nil, err
		}
		req.Entity = append(req.Entity, sProto)
	}
	res := &pb.PutResponse{}
	if err := c.Call("datastore_v3", "Put", req, res, nil); err != nil {
		return nil, err
	}
	if len(key) != len(res.Key) {
		return nil, errors.New("datastore: internal error: server returned the wrong number of keys")
	}
	ret := make([]*Key, len(key))
	for i := range ret {
		var err error
		ret[i], err = protoToKey(res.Key[i])
		if err != nil || ret[i].Incomplete() {
			return nil, errors.New("datastore: internal error: server returned an invalid key")
		}
	}
	return ret, nil
}
Ejemplo n.º 28
0
// Stats retrieves the current memcache statistics.
func Stats(c appengine.Context) (*Statistics, error) {
	req := &pb.MemcacheStatsRequest{}
	res := &pb.MemcacheStatsResponse{}
	if err := c.Call("memcache", "Stats", req, res, nil); err != nil {
		return nil, err
	}
	if res.Stats == nil {
		return nil, ErrNoStats
	}
	return &Statistics{
		Hits:     *res.Stats.Hits,
		Misses:   *res.Stats.Misses,
		ByteHits: *res.Stats.ByteHits,
		Items:    *res.Stats.Items,
		Bytes:    *res.Stats.Bytes,
		Oldest:   int64(*res.Stats.OldestItemAge),
	}, nil
}
Ejemplo n.º 29
0
// CurrentOAuth returns the user associated with the OAuth consumer making this
// request. If the OAuth consumer did not make a valid OAuth request, or the
// scope is non-empty and the current user does not have this scope, this method
// will return an error.
func CurrentOAuth(c appengine.Context, scope string) (*User, error) {
	req := &pb.GetOAuthUserRequest{}
	if scope != "" {
		req.Scope = &scope
	}
	res := &pb.GetOAuthUserResponse{}

	err := c.Call("user", "GetOAuthUser", req, res, nil)
	if err != nil {
		return nil, err
	}
	return &User{
		Email:      *res.Email,
		AuthDomain: *res.AuthDomain,
		Admin:      res.GetIsAdmin(),
		ID:         *res.UserId,
	}, nil
}
Ejemplo n.º 30
0
// AddMulti adds multiple tasks to a named queue.
// An empty queue name means that the default queue will be used.
// AddMulti returns a slice of equivalent tasks with defaults filled in, including setting
// each task's Name field to the chosen name if the original was empty.
// If a given task is badly formed or could not be added, an appengine.MultiError is returned.
func AddMulti(c appengine.Context, tasks []*Task, queueName string) ([]*Task, error) {
	req := &pb.TaskQueueBulkAddRequest{
		AddRequest: make([]*pb.TaskQueueAddRequest, len(tasks)),
	}
	me, any := make(appengine.MultiError, len(tasks)), false
	for i, t := range tasks {
		req.AddRequest[i], me[i] = newAddReq(c, t, queueName)
		any = any || me[i] != nil
	}
	if any {
		return nil, me
	}
	res := &pb.TaskQueueBulkAddResponse{}
	if err := c.Call("taskqueue", "BulkAdd", req, res, nil); err != nil {
		return nil, err
	}
	if len(res.Taskresult) != len(tasks) {
		return nil, errors.New("taskqueue: server error")
	}
	tasksOut := make([]*Task, len(tasks))
	for i, tr := range res.Taskresult {
		tasksOut[i] = new(Task)
		*tasksOut[i] = *tasks[i]
		tasksOut[i].Method = tasksOut[i].method()
		if tasksOut[i].Name == "" {
			tasksOut[i].Name = string(tr.ChosenTaskName)
		}
		if *tr.Result != pb.TaskQueueServiceError_OK {
			if alreadyAddedErrors[*tr.Result] {
				me[i] = ErrTaskAlreadyAdded
			} else {
				me[i] = &internal.APIError{
					Service: "taskqueue",
					Code:    int32(*tr.Result),
				}
			}
			any = true
		}
	}
	if any {
		return tasksOut, me
	}
	return tasksOut, nil
}