diff --git a/TODO b/TODO index d9cf08517..0e750351a 100644 --- a/TODO +++ b/TODO @@ -4,6 +4,15 @@ There are two TODO lists. This file (good for airplanes) and the online bug trac Offline list: +-- camput's havecache initialization should move up a layer to + to be global to all commands, not specific to "camput file". + (the statcache can stay in file). otherwise, we have no haveCache + on the pkg/client.*Client and the UploadAndSignBlob call (for + creating permanodes and other claims) can't efficiently upload its + public key if the server doesn't already have it. currently it + has to try to upload it (doing a remote HTTP stat) each time + when using "camput permanode" or "camput attr". + -- use 'int' instead of 'int64' for blob sizes everywhere. blobs have a max size of 10-32 MB anyway. definitely not bigger than what will fit in memory (which is what int means) diff --git a/pkg/client/client.go b/pkg/client/client.go index 3b447267f..dd506f70b 100644 --- a/pkg/client/client.go +++ b/pkg/client/client.go @@ -802,13 +802,13 @@ func (c *Client) initEntityFetcher() { // sigTime optionally specifies the signature time. // If zero, the current time is used. func (c *Client) SignBlob(bb schema.Buildable, sigTime time.Time) (string, error) { - camliSigBlobref := c.SignerPublicKeyBlobref() - if !camliSigBlobref.Valid() { + sigRef := c.SignerPublicKeyBlobref() + if !sigRef.Valid() { // TODO: more helpful error message return "", errors.New("No public key configured.") } - b := bb.Builder().SetSigner(camliSigBlobref).Blob() + b := bb.Builder().SetSigner(sigRef).Blob() return c.Sign(&jsonsign.SignRequest{ UnsignedJSON: b.JSON(), SignatureTime: sigTime, @@ -820,6 +820,20 @@ func (c *Client) UploadAndSignBlob(b schema.AnyBlob) (*PutResult, error) { if err != nil { return nil, err } + + // sigRef is guaranteed valid at this point, because SignBlob + // succeeded. If we don't know for sure that the server + // already has this public key, upload it. And do it serially + // so by the time we do the second upload of the signed blob, + // any synchronous indexing on the server won't fail due to a + // missing public key. + sigRef := c.SignerPublicKeyBlobref() + if _, keyUploaded := c.haveCache.StatBlobCache(sigRef); !keyUploaded { + if _, err := c.uploadString(publicKeyArmored); err != nil { + return nil, err + } + } + return c.uploadString(signed) } diff --git a/pkg/client/config.go b/pkg/client/config.go index 648fd93d1..a2d346610 100644 --- a/pkg/client/config.go +++ b/pkg/client/config.go @@ -192,7 +192,8 @@ func fileExists(name string) bool { var ( signerPublicKeyRefOnce sync.Once - signerPublicKeyRef blob.Ref + signerPublicKeyRef blob.Ref // of publicKeyArmored + publicKeyArmored string ) // TODO: move to config package? @@ -202,10 +203,10 @@ func SignerPublicKeyBlobref() blob.Ref { } func initSignerPublicKeyBlobref() { - signerPublicKeyRef, _ = getSignerPublicKeyBlobref() + signerPublicKeyRef, publicKeyArmored, _ = getSignerPublicKeyBlobref() } -func getSignerPublicKeyBlobref() (signerRef blob.Ref, ok bool) { +func getSignerPublicKeyBlobref() (signerRef blob.Ref, armored string, ok bool) { configOnce.Do(parseConfig) key := "keyId" keyId, ok := config[key].(string) @@ -229,7 +230,7 @@ func getSignerPublicKeyBlobref() (signerRef blob.Ref, ok bool) { log.Printf("Couldn't find keyId %q in secret ring: %v", keyId, err) return } - armored, err := jsonsign.ArmoredPublicKey(entity) + armored, err = jsonsign.ArmoredPublicKey(entity) if err != nil { log.Printf("Error serializing public key: %v", err) return @@ -259,7 +260,7 @@ func getSignerPublicKeyBlobref() (signerRef blob.Ref, ok bool) { } } - return br, true + return br, armored, true } func (c *Client) GetBlobFetcher() blob.SeekFetcher {