Fix for Go weekly.2012-01-15.
@@ -7,10 +7,10 @@
import ( "bytes" "encoding/binary" - "math" - "os" - "rand" "io" + + "math" + "math/rand" ) const sampleRate = 8000 // Hz@@ -24,7 +24,7 @@ endingBeepSound = changeSpeed(beepSound, 1.4)
} type Audio struct { - body *bytes.Buffer + body *bytes.Buffer digitSounds [][]byte }@@ -79,7 +79,7 @@ }
// WriteTo writes captcha audio in WAVE format into the given io.Writer, and // returns the number of bytes written and an error if any. -func (a *Audio) WriteTo(w io.Writer) (n int64, err os.Error) { +func (a *Audio) WriteTo(w io.Writer) (n int64, err error) { // Calculate padded length of PCM chunk data. bodyLen := uint32(a.body.Len()) paddedBodyLen := bodyLen
@@ -47,8 +47,8 @@ package captcha
import ( "bytes" + "errors" "io" - "os" ) const (@@ -62,7 +62,7 @@ Expiration = 10 * 60 // 10 minutes
) var ( - ErrNotFound = os.NewError("captcha: id not found") + ErrNotFound = errors.New("captcha: id not found") // globalStore is a shared storage for captchas, generated by New function. globalStore = NewMemoryStore(CollectNum, Expiration) )@@ -104,7 +104,7 @@ }
// WriteImage writes PNG-encoded image representation of the captcha with the // given id. The image will have the given width and height. -func WriteImage(w io.Writer, id string, width, height int) os.Error { +func WriteImage(w io.Writer, id string, width, height int) error { d := globalStore.Get(id, false) if d == nil { return ErrNotFound@@ -116,7 +116,7 @@
// WriteAudio writes WAV-encoded audio representation of the captcha with the // given id and the given language. If there are no sounds for the given // language, English is used. -func WriteAudio(w io.Writer, id string, lang string) os.Error { +func WriteAudio(w io.Writer, id string, lang string) error { d := globalStore.Get(id, false) if d == nil { return ErrNotFound
@@ -8,10 +8,10 @@
import ( "fmt" "github.com/dchest/captcha" - "http" "io" "log" - "template" + "net/http" + "text/template" ) var formTemplate = template.Must(template.New("example").Parse(formTemplateSrc))@@ -22,12 +22,12 @@ http.NotFound(w, r)
return } d := struct { - CaptchaId string + CaptchaId string }{ captcha.New(), } if err := formTemplate.Execute(w, &d); err != nil { - http.Error(w, err.String(), http.StatusInternalServerError) + http.Error(w, err.Error(), http.StatusInternalServerError) } }
@@ -10,8 +10,7 @@ "image/color"
"image/png" "io" "math" - "os" - "rand" + "math/rand" ) const (@@ -86,7 +85,7 @@ // method returns 0 instead of the actual bytes written because png.Encode
// doesn't report this. // WriteTo writes captcha image in PNG format into the given writer. -func (m *Image) WriteTo(w io.Writer) (int64, os.Error) { +func (m *Image) WriteTo(w io.Writer) (int64, error) { return 0, png.Encode(w, m.Paletted) }
@@ -4,16 +4,13 @@ // license that can be found in the LICENSE file.
package captcha -import ( - "os" - "testing" -) +import "testing" type byteCounter struct { n int64 } -func (bc *byteCounter) Write(b []byte) (int, os.Error) { +func (bc *byteCounter) Write(b []byte) (int, error) { bc.n += int64(len(b)) return len(b), nil }
@@ -7,7 +7,7 @@
import ( crand "crypto/rand" "io" - "rand" + "math/rand" "time" )@@ -18,7 +18,7 @@ // idChars are characters allowed in captcha id.
var idChars = []byte("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789") func init() { - rand.Seed(time.Nanoseconds()) + rand.Seed(time.Now().UnixNano()) } // RandomDigits returns a byte slice of the given length containing@@ -32,7 +32,7 @@ // randomBytes returns a byte slice of the given length read from CSPRNG.
func randomBytes(length int) (b []byte) { b = make([]byte, length) if _, err := io.ReadFull(crand.Reader, b); err != nil { - panic("captcha: error reading random source: " + err.String()) + panic("captcha: error reading random source: " + err.Error()) } return }
@@ -5,8 +5,7 @@
package captcha import ( - "http" - "os" + "net/http" "path" "strconv" "strings"@@ -39,11 +38,11 @@ //
// By default, the Server serves audio in English language. To serve audio // captcha in one of the other supported languages, append "lang" value, for // example, "?lang=ru". -func Server(imgWidth, imgHeight int) http.Handler { +func Server(imgWidth, imgHeight int) http.Handler { return &captchaHandler{imgWidth, imgHeight} } -func (h *captchaHandler) serve(w http.ResponseWriter, id, ext string, lang string, download bool) os.Error { +func (h *captchaHandler) serve(w http.ResponseWriter, id, ext string, lang string, download bool) error { if download { w.Header().Set("Content-Type", "application/octet-stream") }
@@ -30,7 +30,7 @@ // expValue stores timestamp and id of captchas. It is used in the list inside
// memoryStore for indexing generated captchas by timestamp to enable garbage // collection of expired captchas. type idByTimeValue struct { - timestamp int64 + timestamp time.Time id string }@@ -44,13 +44,13 @@ numStored int
// Number of saved items that triggers collection. collectNum int // Expiration time of captchas. - expiration int64 + expiration time.Duration } // NewMemoryStore returns a new standard memory store for captchas with the -// given collection threshold and expiration time in seconds. The returned +// given collection threshold and expiration time (duration). The returned // store must be registered with SetCustomStore to replace the default one. -func NewMemoryStore(collectNum int, expiration int64) Store { +func NewMemoryStore(collectNum int, expiration time.Duration) Store { s := new(memoryStore) s.digitsById = make(map[string][]byte) s.idByTime = list.New()@@ -62,7 +62,7 @@
func (s *memoryStore) Set(id string, digits []byte) { s.mu.Lock() s.digitsById[id] = digits - s.idByTime.PushBack(idByTimeValue{time.Seconds(), id}) + s.idByTime.PushBack(idByTimeValue{time.Now(), id}) s.numStored++ if s.numStored <= s.collectNum { s.mu.Unlock()@@ -86,7 +86,7 @@ if !ok {
return } if clear { - s.digitsById[id] = nil, false + delete(s.digitsById, id) // XXX(dchest) Index (s.idByTime) will be cleaned when // collecting expired captchas. Can't clean it here, because // we don't store reference to expValue in the map.@@ -96,7 +96,7 @@ return
} func (s *memoryStore) collect() { - now := time.Seconds() + now := time.Now() s.mu.Lock() defer s.mu.Unlock() s.numStored = 0@@ -105,8 +105,8 @@ ev, ok := e.Value.(idByTimeValue)
if !ok { return } - if ev.timestamp+s.expiration < now { - s.digitsById[ev.id] = nil, false + if ev.timestamp.Add(s.expiration).Before(now) { + delete(s.digitsById, ev.id) next := e.Next() s.idByTime.Remove(e) e = next