Пример #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 or
// FieldMetadataLoadSaver interface.
//
// If dst is a struct pointer, then fields which are missing or unexported in
// the destination struct are silently ignored.
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)
}
Пример #2
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)
}
Пример #3
0
// GetPresence retrieves a user's 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".
// ErrPresenceUnavailable is returned if the presence is unavailable.
func GetPresence(c appengine.Context, to string, from string) (string, error) {
	req := &xmpp_proto.PresenceRequest{
		Jid: &to,
	}
	if from != "" {
		req.FromJid = &from
	}
	res := &xmpp_proto.PresenceResponse{}
	if err := c.Call("xmpp", "GetPresence", req, res, nil); err != nil {
		return "", err
	}
	if !*res.IsAvailable || res.Presence == nil {
		return "", ErrPresenceUnavailable
	}
	switch *res.Presence {
	case xmpp_proto.PresenceResponse_NORMAL:
		return "", nil
	case xmpp_proto.PresenceResponse_AWAY:
		return "away", nil
	case xmpp_proto.PresenceResponse_DO_NOT_DISTURB:
		return "dnd", nil
	case xmpp_proto.PresenceResponse_CHAT:
		return "chat", nil
	case xmpp_proto.PresenceResponse_EXTENDED_AWAY:
		return "xa", nil
	}
	return "", fmt.Errorf("xmpp: unknown presence %v", *res.Presence)
}
Пример #4
0
// Purge removes all tasks from a queue.
func Purge(c appengine.Context, queueName string) error {
	req := &taskqueue_proto.TaskQueuePurgeQueueRequest{
		QueueName: []byte(queueName),
	}
	res := &taskqueue_proto.TaskQueuePurgeQueueResponse{}
	return c.Call("taskqueue", "PurgeQueue", req, res, nil)
}
Пример #5
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
}
Пример #6
0
// DeleteMulti is a batch version of Delete.
// The returned slice will have the same length as the input slice.
// If a given key cannot be found, its corresponding value in the
// returned error slice is set to ErrCacheMiss.
// 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{}
	e := make([]error, len(key))
	err := c.Call("memcache", "Delete", req, res, nil)
	if err == nil && len(e) != len(res.DeleteStatus) {
		err = ErrServerError
	}
	if err != nil {
		for i := range e {
			e[i] = err
		}
		return e
	}
	for i, s := range res.DeleteStatus {
		switch s {
		case pb.MemcacheDeleteResponse_DELETED:
			e[i] = nil
		case pb.MemcacheDeleteResponse_NOT_FOUND:
			e[i] = ErrCacheMiss
		default:
			e[i] = ErrServerError
		}
	}
	return e
}
Пример #7
0
// Get loads the entity stored for k into dst, which may be either a struct
// pointer or a Map. If there is no such entity for the key, Get returns
// ErrNoSuchEntity.
//
// The values of dst's unmatched struct fields or Map entries are not modified.
// In particular, it is recommended to pass either a pointer to a zero valued
// struct or an empty Map on each Get call.
//
// 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.
func Get(c appengine.Context, k *Key, dst interface{}) os.Error {
	if !k.valid() {
		return ErrInvalidKey
	}
	req := &pb.GetRequest{
		Key: []*pb.Reference{
			keyToProto(c.AppID(), k),
		},
	}
	res := &pb.GetResponse{}
	err := c.Call("datastore_v3", "Get", req, res)
	if err != nil {
		return err
	}
	if len(res.Entity) == 0 || res.Entity[0].Entity == nil {
		return ErrNoSuchEntity
	}
	if m, ok := dst.(Map); ok {
		return loadMap(m, k, res.Entity[0].Entity)
	}
	sv, err := asStructValue(dst)
	if err != nil {
		return err
	}
	return loadStruct(sv, k, res.Entity[0].Entity)
}
Пример #8
0
func lease(c appengine.Context, maxTasks int, queueName string, leaseTime int, groupByTag bool, tag []byte) ([]*Task, error) {
	req := &taskqueue_proto.TaskQueueQueryAndOwnTasksRequest{
		QueueName:    []byte(queueName),
		LeaseSeconds: proto.Float64(float64(leaseTime)),
		MaxTasks:     proto.Int64(int64(maxTasks)),
		GroupByTag:   proto.Bool(groupByTag),
		Tag:          tag,
	}
	res := &taskqueue_proto.TaskQueueQueryAndOwnTasksResponse{}
	callOpts := &appengine_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
}
Пример #9
0
// QueueStats retrieves statistics about queues.
// If maxTasks is greater than zero, the number of tasks scanned will be limited;
// if the number of tasks is greater than maxTasks, the Tasks field will be an approximation.
func QueueStats(c appengine.Context, queueNames []string, maxTasks int) ([]QueueStatistics, error) {
	req := &taskqueue_proto.TaskQueueFetchQueueStatsRequest{
		QueueName: make([][]byte, len(queueNames)),
	}
	for i, q := range queueNames {
		req.QueueName[i] = []byte(q)
	}
	if maxTasks > 0 {
		req.MaxNumTasks = proto.Int32(int32(maxTasks))
	}
	res := &taskqueue_proto.TaskQueueFetchQueueStatsResponse{}
	callOpts := &appengine_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
}
Пример #10
0
// Send sends an email message.
func Send(c appengine.Context, msg *Message) error {
	req := &mail_proto.MailMessage{
		Sender:   &msg.Sender,
		To:       msg.To,
		Cc:       msg.Cc,
		Bcc:      msg.Bcc,
		Subject:  &msg.Subject,
		TextBody: &msg.Body,
	}
	if msg.ReplyTo != "" {
		req.ReplyTo = &msg.ReplyTo
	}
	if len(msg.Attachments) > 0 {
		req.Attachment = make([]*mail_proto.MailAttachment, len(msg.Attachments))
		for i, att := range msg.Attachments {
			req.Attachment[i] = &mail_proto.MailAttachment{
				FileName: &att.Name,
				Data:     att.Data,
			}
		}
	}
	res := &struct{}{} // VoidProto
	if err := c.Call("mail", "Send", req, res, nil); err != nil {
		return err
	}
	return nil
}
Пример #11
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)
	}
	req := &taskqueue_proto.TaskQueueDeleteRequest{
		QueueName: []byte(queueName),
		TaskName:  taskNames,
	}
	res := &taskqueue_proto.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 != taskqueue_proto.TaskQueueServiceError_OK {
			me[i] = &appengine_internal.APIError{
				Service: "taskqueue",
				Code:    int32(ec),
			}
			any = true
		}
	}
	if any {
		return me
	}
	return nil
}
Пример #12
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
}
Пример #13
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 or implement the FieldLoadSaver or
// FieldMetadataLoadSaver interface.
func (x *Index) Put(c appengine.Context, id string, src interface{}) (string, error) {
	d, err := saveDoc(src)
	if err != nil {
		return "", err
	}
	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) > 0 {
		if s := res.Status[0]; s.GetCode() != pb.SearchServiceError_OK {
			return "", fmt.Errorf("search: %s: %s", s.GetCode(), s.GetErrorDetail())
		}
	}
	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))
	}
	return res.DocId[0], nil
}
Пример #14
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
}
Пример #15
0
// Delete deletes a file.
func Delete(c appengine.Context, filename string) error {
	req := &filepb.DeleteRequest{
		Filename: &filename,
	}
	res := new(filepb.DeleteResponse)
	// No fields in response to check.
	return c.Call("file", "Delete", req, res, nil)
}
// Send sends a message on the channel associated with clientID.
func Send(c appengine.Context, clientID, message string) os.Error {
	req := &channel_proto.SendMessageRequest{
		ApplicationKey: &clientID,
		Message:        &message,
	}
	resp := &struct{}{} // VoidProto
	return c.Call(service, "SendChannelMessage", req, resp)
}
Пример #17
0
// Send sends a message on the channel associated with clientID.
func Send(c appengine.Context, clientID, message string) error {
	req := &channel_proto.SendMessageRequest{
		ApplicationKey: &clientID,
		Message:        &message,
	}
	resp := &base_proto.VoidProto{}
	return c.Call(service, "SendChannelMessage", req, resp, nil)
}
Пример #18
0
// Convert converts the document to the given MIME type.
// opts may be nil.
func (d *Document) Convert(c appengine.Context, mimeType string, opts *Options) (*Document, error) {
	req := &conversion_proto.ConversionRequest{
		Conversion: []*conversion_proto.ConversionInput{
			&conversion_proto.ConversionInput{
				Input:          &conversion_proto.DocumentInfo{},
				OutputMimeType: &mimeType,
			},
		},
	}
	for _, asset := range d.Assets {
		a := &conversion_proto.AssetInfo{
			Data: asset.Data,
		}
		if asset.Name != "" {
			a.Name = &asset.Name
		}
		if asset.Type != "" {
			a.MimeType = &asset.Type
		}
		req.Conversion[0].Input.Asset = append(req.Conversion[0].Input.Asset, a)
	}
	if opts != nil {
		f, err := opts.toFlags()
		if err != nil {
			return nil, err
		}
		for k, v := range f {
			req.Conversion[0].Flag = append(req.Conversion[0].Flag, &conversion_proto.ConversionInput_AuxData{
				Key:   proto.String(k),
				Value: proto.String(v),
			})
		}
	}
	res := &conversion_proto.ConversionResponse{}
	if err := c.Call("conversion", "Convert", req, res, nil); err != nil {
		return nil, err
	}
	// We only support one conversion at a time, so the following code assumes that.
	if len(res.Result) != 1 {
		return nil, fmt.Errorf("conversion: requested conversion of one doc, but got %d back", len(res.Result))
	}
	if ec := *res.Result[0].ErrorCode; ec != conversion_proto.ConversionServiceError_OK {
		return nil, fmt.Errorf("conversion: operation failed: %v", ec)
	}
	output := res.Result[0].Output
	if output == nil {
		return nil, errors.New("conversion: output is nil")
	}
	doc := &Document{}
	for _, asset := range output.Asset {
		doc.Assets = append(doc.Assets, Asset{
			Name: asset.GetName(),
			Data: asset.Data,
			Type: asset.GetMimeType(),
		})
	}
	return doc, nil
}
// Create creates a channel and returns a token for use by the client.
// The clientID is an appication-provided string used to identify the client.
func Create(c appengine.Context, clientID string) (token string, err os.Error) {
	req := &channel_proto.CreateChannelRequest{
		ApplicationKey: &clientID,
	}
	resp := &channel_proto.CreateChannelResponse{}
	err = c.Call("channel", "CreateChannel", req, resp)
	token = proto.GetString(resp.ClientId)
	return
}
Пример #20
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
}
// set sets the given items using the given conflict resolution policy.
// The returned slice will have the same length as the input slice.
// If value is not nil, each element should correspond to an item.
func set(c appengine.Context, item []*Item, value [][]byte, policy int32) []os.Error {
	req := &pb.MemcacheSetRequest{
		Item: make([]*pb.MemcacheSetRequest_Item, len(item)),
	}
	for i, t := range item {
		p := &pb.MemcacheSetRequest_Item{
			Key: []byte(t.Key),
		}
		if value == nil {
			p.Value = t.Value
		} else {
			p.Value = value[i]
		}
		if t.Flags != 0 {
			p.Flags = proto.Uint32(t.Flags)
		}
		if t.Expiration != 0 {
			// In the .proto file, MemcacheSetRequest_Item uses a fixed32 (i.e. unsigned)
			// for expiration time, while MemcacheGetRequest_Item uses int32 (i.e. signed).
			// Throughout this .go file, we use int32.
			p.ExpirationTime = proto.Uint32(uint32(t.Expiration))
		}
		if t.casID != 0 {
			p.CasId = proto.Uint64(t.casID)
			p.ForCas = proto.Bool(true)
		}
		p.SetPolicy = pb.NewMemcacheSetRequest_SetPolicy(policy)
		req.Item[i] = p
	}
	res := &pb.MemcacheSetResponse{}
	e := make([]os.Error, len(item))
	if err := c.Call("memcache", "Set", req, res); err != nil {
		for i := range e {
			e[i] = err
		}
		return e
	}
	if len(e) != len(res.SetStatus) {
		for i := range e {
			e[i] = ErrServerError
		}
		return e
	}
	for i := range e {
		switch res.SetStatus[i] {
		case pb.MemcacheSetResponse_STORED:
			e[i] = nil
		case pb.MemcacheSetResponse_NOT_STORED:
			e[i] = ErrNotStored
		case pb.MemcacheSetResponse_EXISTS:
			e[i] = ErrCASConflict
		default:
			e[i] = ErrServerError
		}
	}
	return e
}
Пример #22
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 := &channel_proto.CreateChannelRequest{
		ApplicationKey: &clientID,
	}
	resp := &channel_proto.CreateChannelResponse{}
	err = c.Call(service, "CreateChannel", req, resp, nil)
	token = resp.GetToken()
	return
}
Пример #23
0
// RunInBackground runs f in a background goroutine in this process.
// This is only valid to invoke from a backend.
func RunInBackground(c appengine.Context, f func(c appengine.Context)) error {
	req := &system_proto.StartBackgroundRequestRequest{}
	res := &system_proto.StartBackgroundRequestResponse{}
	if err := c.Call("system", "StartBackgroundRequest", req, res, nil); err != nil {
		return err
	}
	sendc <- send{res.GetRequestId(), f}
	return nil
}
Пример #24
0
// BlobKeyForFile returns a BlobKey for a Google Storage file.
// The filename should be of the form "/gs/bucket_name/object_name".
func BlobKeyForFile(c appengine.Context, filename string) (appengine.BlobKey, error) {
	req := &blobpb.CreateEncodedGoogleStorageKeyRequest{
		Filename: &filename,
	}
	res := &blobpb.CreateEncodedGoogleStorageKeyResponse{}
	if err := c.Call("blobstore", "CreateEncodedGoogleStorageKey", req, res, nil); err != nil {
		return "", err
	}
	return appengine.BlobKey(*res.BlobKey), nil
}
Пример #25
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)
}
Пример #26
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)
}
Пример #27
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
}
Пример #28
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
}
// UploadURL creates an upload URL for the form that the user will fill out,
// passing the application path to load when the POST of the form is
// completed. These URLs expire and should not be reused.
func UploadURL(c appengine.Context, successPath string) (*http.URL, os.Error) {
	req := &pb.CreateUploadURLRequest{
		SuccessPath: proto.String(successPath),
	}
	res := &pb.CreateUploadURLResponse{}
	if err := c.Call("blobstore", "CreateUploadURL", req, res); err != nil {
		return nil, err
	}
	return http.ParseURL(*res.Url)
}
Пример #30
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
}