2012-04-21 14:14:57 +00:00
|
|
|
/*
|
|
|
|
Copyright 2012 Google Inc.
|
|
|
|
|
|
|
|
Licensed under the Apache License, Version 2.0 (the "License");
|
|
|
|
you may not use this file except in compliance with the License.
|
|
|
|
You may obtain a copy of the License at
|
|
|
|
|
|
|
|
http://www.apache.org/licenses/LICENSE-2.0
|
|
|
|
|
|
|
|
Unless required by applicable law or agreed to in writing, software
|
|
|
|
distributed under the License is distributed on an "AS IS" BASIS,
|
|
|
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
|
|
See the License for the specific language governing permissions and
|
|
|
|
limitations under the License.
|
|
|
|
*/
|
|
|
|
|
|
|
|
package main
|
|
|
|
|
|
|
|
import (
|
|
|
|
"errors"
|
|
|
|
"net/http"
|
2012-10-22 09:42:44 +00:00
|
|
|
"strings"
|
2012-07-28 23:32:31 +00:00
|
|
|
"time"
|
2012-04-21 14:14:57 +00:00
|
|
|
|
|
|
|
"camlistore.org/pkg/blobserver"
|
|
|
|
"camlistore.org/pkg/client"
|
2013-01-03 04:32:13 +00:00
|
|
|
"camlistore.org/pkg/httputil"
|
2012-04-21 14:14:57 +00:00
|
|
|
"camlistore.org/pkg/jsonsign"
|
|
|
|
"camlistore.org/pkg/schema"
|
|
|
|
)
|
|
|
|
|
|
|
|
type Uploader struct {
|
|
|
|
*client.Client
|
|
|
|
|
2012-11-08 04:21:52 +00:00
|
|
|
fileOpts *fileOptions // per-file options; may be nil
|
2012-04-21 14:14:57 +00:00
|
|
|
|
|
|
|
// for debugging; normally nil, but overrides Client if set
|
|
|
|
// TODO(bradfitz): clean this up? embed a StatReceiver instead
|
|
|
|
// of a Client?
|
|
|
|
altStatReceiver blobserver.StatReceiver
|
|
|
|
|
|
|
|
entityFetcher jsonsign.EntityFetcher
|
|
|
|
|
2013-01-03 04:32:13 +00:00
|
|
|
transport *httputil.StatsTransport // for HTTP statistics
|
2012-04-21 14:14:57 +00:00
|
|
|
pwd string
|
|
|
|
statCache UploadCache
|
|
|
|
haveCache HaveCache
|
|
|
|
|
|
|
|
fs http.FileSystem // virtual filesystem to read from; nil means OS filesystem.
|
|
|
|
}
|
|
|
|
|
2012-10-22 09:42:44 +00:00
|
|
|
// possible options when uploading a file
|
|
|
|
type fileOptions struct {
|
|
|
|
permanode bool // create a content-based permanode for each uploaded file
|
|
|
|
// tag is an optional tag or comma-delimited tags to apply to
|
|
|
|
// the above permanode.
|
2013-01-07 19:15:18 +00:00
|
|
|
tag string
|
|
|
|
// perform for the client the actions needing gpg signing when uploading a file.
|
|
|
|
vivify bool
|
|
|
|
exifTime bool // use the time in exif metadata as the modtime if possible.
|
2012-10-22 09:42:44 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
func (o *fileOptions) tags() []string {
|
|
|
|
if o == nil || o.tag == "" {
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
return strings.Split(o.tag, ",")
|
|
|
|
}
|
|
|
|
|
|
|
|
func (o *fileOptions) wantFilePermanode() bool {
|
|
|
|
return o != nil && o.permanode
|
|
|
|
}
|
|
|
|
|
2012-12-20 17:34:14 +00:00
|
|
|
func (o *fileOptions) wantVivify() bool {
|
|
|
|
return o != nil && o.vivify
|
|
|
|
}
|
|
|
|
|
2012-07-28 23:32:31 +00:00
|
|
|
// sigTime optionally specifies the signature time.
|
|
|
|
// If zero, the current time is used.
|
2013-01-22 01:31:08 +00:00
|
|
|
func (up *Uploader) SignBlob(bb schema.Buildable, sigTime time.Time) (string, error) {
|
2012-04-21 14:14:57 +00:00
|
|
|
camliSigBlobref := up.Client.SignerPublicKeyBlobref()
|
|
|
|
if camliSigBlobref == nil {
|
|
|
|
// TODO: more helpful error message
|
|
|
|
return "", errors.New("No public key configured.")
|
|
|
|
}
|
|
|
|
|
2013-01-22 01:31:08 +00:00
|
|
|
b := bb.Builder().SetSigner(camliSigBlobref).Blob()
|
2012-04-21 14:14:57 +00:00
|
|
|
sr := &jsonsign.SignRequest{
|
2013-01-22 01:31:08 +00:00
|
|
|
UnsignedJSON: b.JSON(),
|
2012-04-21 14:14:57 +00:00
|
|
|
Fetcher: up.Client.GetBlobFetcher(),
|
|
|
|
EntityFetcher: up.entityFetcher,
|
2012-07-28 23:32:31 +00:00
|
|
|
SignatureTime: sigTime,
|
2012-04-21 14:14:57 +00:00
|
|
|
}
|
|
|
|
return sr.Sign()
|
|
|
|
}
|
|
|
|
|
2013-01-22 01:31:08 +00:00
|
|
|
func (up *Uploader) UploadAndSignBlob(b schema.AnyBlob) (*client.PutResult, error) {
|
|
|
|
signed, err := up.SignBlob(b.Blob(), time.Time{})
|
2012-04-21 14:14:57 +00:00
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
2013-01-22 01:31:08 +00:00
|
|
|
return up.uploadString(signed)
|
2012-04-21 14:14:57 +00:00
|
|
|
}
|
|
|
|
|
2013-01-22 01:31:08 +00:00
|
|
|
func (up *Uploader) UploadBlob(b schema.AnyBlob) (*client.PutResult, error) {
|
|
|
|
// TODO(bradfitz): ask the blob for its own blobref, rather
|
|
|
|
// than changing the hash function with uploadString?
|
|
|
|
return up.uploadString(b.Blob().JSON())
|
2012-04-21 14:14:57 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
func (up *Uploader) uploadString(s string) (*client.PutResult, error) {
|
2013-01-02 04:23:44 +00:00
|
|
|
return up.Upload(client.NewUploadHandleFromString(s))
|
2012-04-21 14:14:57 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
func (up *Uploader) UploadNewPermanode() (*client.PutResult, error) {
|
|
|
|
unsigned := schema.NewUnsignedPermanode()
|
2013-01-22 01:31:08 +00:00
|
|
|
return up.UploadAndSignBlob(unsigned)
|
2012-04-21 14:14:57 +00:00
|
|
|
}
|
2012-07-28 23:32:31 +00:00
|
|
|
|
|
|
|
func (up *Uploader) UploadPlannedPermanode(key string, sigTime time.Time) (*client.PutResult, error) {
|
|
|
|
unsigned := schema.NewPlannedPermanode(key)
|
2013-01-22 01:31:08 +00:00
|
|
|
signed, err := up.SignBlob(unsigned, sigTime)
|
2012-08-21 06:11:10 +00:00
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
2012-07-28 23:32:31 +00:00
|
|
|
return up.uploadString(signed)
|
|
|
|
}
|