// propValue returns a Go value that combines the raw PropertyValue with a // meaning. For example, an Int64Value with GD_WHEN becomes a time.Time. func propValue(v *pb.PropertyValue, m pb.Property_Meaning) (interface{}, error) { switch { case v.Int64Value != nil: if m == pb.Property_GD_WHEN { return fromUnixMicro(*v.Int64Value), nil } else { return *v.Int64Value, nil } case v.BooleanValue != nil: return *v.BooleanValue, nil case v.StringValue != nil: if m == pb.Property_BLOB { return []byte(*v.StringValue), nil } else if m == pb.Property_BLOBKEY { return appengine.BlobKey(*v.StringValue), nil } else if m == pb.Property_BYTESTRING { return ByteString(*v.StringValue), nil } else { return *v.StringValue, nil } case v.DoubleValue != nil: return *v.DoubleValue, nil case v.Referencevalue != nil: key, err := referenceValueToKey(v.Referencevalue) if err != nil { return nil, err } return key, nil case v.Pointvalue != nil: // NOTE: Strangely, latitude maps to X, longitude to Y. return appengine.GeoPoint{Lat: v.Pointvalue.GetX(), Lng: v.Pointvalue.GetY()}, nil } return nil, nil }
// BlobKeyForFile returns a BlobKey for a Google Storage file. // The filename should be of the form "/gs/bucket_name/object_name". func BlobKeyForFile(c context.Context, filename string) (appengine.BlobKey, error) { req := &blobpb.CreateEncodedGoogleStorageKeyRequest{ Filename: &filename, } res := &blobpb.CreateEncodedGoogleStorageKeyResponse{} if err := internal.Call(c, "blobstore", "CreateEncodedGoogleStorageKey", req, res); err != nil { return "", err } return appengine.BlobKey(*res.BlobKey), nil }
// ParseUpload parses the synthetic POST request that your app gets from // App Engine after a user's successful upload of blobs. Given the request, // ParseUpload returns a map of the blobs received (keyed by HTML form // element name) and other non-blob POST parameters. func ParseUpload(req *http.Request) (blobs map[string][]*BlobInfo, other url.Values, err error) { _, params, err := mime.ParseMediaType(req.Header.Get("Content-Type")) if err != nil { return nil, nil, err } boundary := params["boundary"] if boundary == "" { return nil, nil, errorf("did not find MIME multipart boundary") } blobs = make(map[string][]*BlobInfo) other = make(url.Values) mreader := multipart.NewReader(io.MultiReader(req.Body, strings.NewReader("\r\n\r\n")), boundary) for { part, perr := mreader.NextPart() if perr == io.EOF { break } if perr != nil { return nil, nil, errorf("error reading next mime part with boundary %q (len=%d): %v", boundary, len(boundary), perr) } bi := &BlobInfo{} ctype, params, err := mime.ParseMediaType(part.Header.Get("Content-Disposition")) if err != nil { return nil, nil, err } bi.Filename = params["filename"] formKey := params["name"] ctype, params, err = mime.ParseMediaType(part.Header.Get("Content-Type")) if err != nil { return nil, nil, err } bi.BlobKey = appengine.BlobKey(params["blob-key"]) if ctype != "message/external-body" || bi.BlobKey == "" { if formKey != "" { slurp, serr := ioutil.ReadAll(part) if serr != nil { return nil, nil, errorf("error reading %q MIME part", formKey) } other[formKey] = append(other[formKey], string(slurp)) } continue } // App Engine sends a MIME header as the body of each MIME part. tp := textproto.NewReader(bufio.NewReader(part)) header, mimeerr := tp.ReadMIMEHeader() if mimeerr != nil { return nil, nil, mimeerr } bi.Size, err = strconv.ParseInt(header.Get("Content-Length"), 10, 64) if err != nil { return nil, nil, err } bi.ContentType = header.Get("Content-Type") // Parse the time from the MIME header like: // X-AppEngine-Upload-Creation: 2011-03-15 21:38:34.712136 createDate := header.Get("X-AppEngine-Upload-Creation") if createDate == "" { return nil, nil, errorf("expected to find an X-AppEngine-Upload-Creation header") } bi.CreationTime, err = time.Parse("2006-01-02 15:04:05.000000", createDate) if err != nil { return nil, nil, errorf("error parsing X-AppEngine-Upload-Creation: %s", err) } if hdr := header.Get("Content-MD5"); hdr != "" { md5, err := base64.URLEncoding.DecodeString(hdr) if err != nil { return nil, nil, errorf("bad Content-MD5 %q: %v", hdr, err) } bi.MD5 = string(md5) } // If the GCS object name was provided, record it. bi.ObjectName = header.Get("X-AppEngine-Cloud-Storage-Object") blobs[formKey] = append(blobs[formKey], bi) } return }
"github.com/nildev/account/Godeps/_workspace/src/github.com/golang/protobuf/proto" "github.com/nildev/account/Godeps/_workspace/src/golang.org/x/net/context" "github.com/nildev/account/Godeps/_workspace/src/google.golang.org/appengine" "github.com/nildev/account/Godeps/_workspace/src/google.golang.org/appengine/datastore" "github.com/nildev/account/Godeps/_workspace/src/google.golang.org/appengine/internal" basepb "github.com/nildev/account/Godeps/_workspace/src/google.golang.org/appengine/internal/base" blobpb "github.com/nildev/account/Godeps/_workspace/src/google.golang.org/appengine/internal/blobstore" ) const ( blobInfoKind = "__BlobInfo__" blobFileIndexKind = "__BlobFileIndex__" zeroKey = appengine.BlobKey("") ) // BlobInfo is the blob metadata that is stored in the datastore. // Filename may be empty. type BlobInfo struct { BlobKey appengine.BlobKey ContentType string `datastore:"content_type"` CreationTime time.Time `datastore:"creation"` Filename string `datastore:"filename"` Size int64 `datastore:"size"` MD5 string `datastore:"md5_hash"` // ObjectName is the Google Cloud Storage name for this blob. ObjectName string `datastore:"gs_object_name"` }
// Use of this source code is governed by the Apache 2.0 // license that can be found in the LICENSE file. package datastore import ( "fmt" "reflect" "time" "github.com/nildev/account/Godeps/_workspace/src/google.golang.org/appengine" pb "github.com/nildev/account/Godeps/_workspace/src/google.golang.org/appengine/internal/datastore" ) var ( typeOfBlobKey = reflect.TypeOf(appengine.BlobKey("")) typeOfByteSlice = reflect.TypeOf([]byte(nil)) typeOfByteString = reflect.TypeOf(ByteString(nil)) typeOfGeoPoint = reflect.TypeOf(appengine.GeoPoint{}) typeOfTime = reflect.TypeOf(time.Time{}) ) // typeMismatchReason returns a string explaining why the property p could not // be stored in an entity field of type v.Type(). func typeMismatchReason(p Property, v reflect.Value) string { entityType := "empty" switch p.Value.(type) { case int64: entityType = "int" case bool: entityType = "bool"