generated from clevergo/pkg-template
-
Notifications
You must be signed in to change notification settings - Fork 8
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
13 changed files
with
291 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,12 @@ | ||
// Copyright 2020 CleverGo. All rights reserved. | ||
// Use of this source code is governed by a BSD-style license that can be found | ||
// in the LICENSE file. | ||
|
||
package dbstore | ||
|
||
type Dialect interface { | ||
Insert(table string) string | ||
Delete(table string) string | ||
QueryRow(table string) string | ||
DeleteExpired(table string) string | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,5 @@ | ||
module github.com/clevergo/captchas/dbstore | ||
|
||
go 1.14 | ||
|
||
require github.com/clevergo/captchas v0.3.2 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,2 @@ | ||
github.com/clevergo/captchas v0.3.2 h1:/P/Lc8umYp052aGeyiQf8a8mED+g+lmZLqmogMrt1e0= | ||
github.com/clevergo/captchas v0.3.2/go.mod h1:MgQIvLx9mhOoScMJnSFvXuqbAQVIwWtLJ862K1jRvR8= |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,7 @@ | ||
CREATE TABLE captchas ( | ||
id VARCHAR(64) NOT NULL PRIMARY KEY, | ||
answer VARCHAR(32) NOT NULL, | ||
created_at BIGINT NOT NULL, | ||
expires_in BIGINT NOT NULL, | ||
INDEX(expires_in) | ||
); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,8 @@ | ||
CREATE TABLE captchas ( | ||
id VARCHAR(64) NOT NULL PRIMARY KEY, | ||
answer VARCHAR(32) NOT NULL, | ||
created_at BIGINT NOT NULL, | ||
expires_in BIGINT NOT null | ||
); | ||
|
||
CREATE INDEX captchas_expires_on_idx ON captchas (expires_in); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,9 @@ | ||
BEGIN; | ||
CREATE TABLE captchas ( | ||
id VARCHAR(64) NOT NULL PRIMARY KEY, | ||
answer VARCHAR(32) NOT NULL, | ||
created_at BIGINT NOT NULL, | ||
expires_in BIGINT NOT NULL | ||
); | ||
CREATE INDEX captchas_expires_in_idx ON captchas (expires_in); | ||
COMMIT; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,122 @@ | ||
// Copyright 2020 CleverGo. All rights reserved. | ||
// Use of this source code is governed by a BSD-style license that can be found | ||
// in the LICENSE file. | ||
|
||
package dbstore | ||
|
||
import ( | ||
"database/sql" | ||
"time" | ||
|
||
"github.com/clevergo/captchas" | ||
) | ||
|
||
type item struct { | ||
ID string `db:"id"` | ||
Answer string `db:"answer"` | ||
CreatedAt int64 `db:"created_at"` | ||
ExpiresIn int64 `db:"expires_in"` | ||
} | ||
|
||
// Option is a function that receives a pointer of store. | ||
type Option func(*Store) | ||
|
||
// Expiration sets expiration. | ||
func Expiration(expiration time.Duration) Option { | ||
return func(s *Store) { | ||
s.expiration = expiration | ||
} | ||
} | ||
|
||
// GCInterval sets garbage collection . | ||
func GCInterval(interval time.Duration) Option { | ||
return func(s *Store) { | ||
s.gcInterval = interval | ||
} | ||
} | ||
|
||
type Store struct { | ||
db *sql.DB | ||
dialect Dialect | ||
tableName string | ||
prefix string | ||
expiration time.Duration | ||
gcInterval time.Duration | ||
} | ||
|
||
// New returns a db store. | ||
func New(db *sql.DB, dialect Dialect, opts ...Option) *Store { | ||
s := &Store{ | ||
db: db, | ||
dialect: dialect, | ||
tableName: "captchas", | ||
prefix: "default", | ||
expiration: 10 * time.Minute, | ||
gcInterval: time.Hour, | ||
} | ||
|
||
for _, f := range opts { | ||
f(s) | ||
} | ||
|
||
go s.gc() | ||
|
||
return s | ||
} | ||
|
||
func (s *Store) getID(id string) string { | ||
return s.prefix + ":" + id | ||
} | ||
|
||
// Get implements Store.Get. | ||
func (s *Store) Get(id string, clear bool) (string, error) { | ||
id = s.getID(id) | ||
row := s.db.QueryRow(s.dialect.QueryRow(s.tableName), id) | ||
if row == nil { | ||
return "", captchas.ErrCaptchaIncorrect | ||
} | ||
item := item{} | ||
if err := row.Scan(&item.ID, &item.Answer, &item.ExpiresIn); err != nil { | ||
if err == sql.ErrNoRows { | ||
return "", captchas.ErrCaptchaIncorrect | ||
} | ||
return "", err | ||
} | ||
if time.Now().Unix() > item.ExpiresIn { | ||
return "", captchas.ErrCaptchaExpired | ||
} | ||
|
||
if clear { | ||
_, err := s.db.Exec(s.dialect.Delete(s.tableName), id) | ||
if err != nil { | ||
return "", err | ||
} | ||
} | ||
|
||
return item.Answer, nil | ||
} | ||
|
||
// Set implements Store.Set. | ||
func (s *Store) Set(id, answer string) error { | ||
id = s.getID(id) | ||
now := time.Now() | ||
_, err := s.db.Exec( | ||
s.dialect.Insert(s.tableName), | ||
id, answer, now.Unix(), now.Add(s.expiration).Unix(), | ||
) | ||
return err | ||
} | ||
|
||
func (s *Store) gc() { | ||
ticker := time.NewTicker(s.gcInterval) | ||
for { | ||
select { | ||
case <-ticker.C: | ||
s.deleteExpired() | ||
} | ||
} | ||
} | ||
|
||
func (s *Store) deleteExpired() { | ||
s.db.Exec(s.dialect.DeleteExpired(s.tableName), time.Now().Unix()) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,3 @@ | ||
module github.com/clevergo/captchas/mysqlstore | ||
|
||
go 1.14 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,39 @@ | ||
// Copyright 2020 CleverGo. All rights reserved. | ||
// Use of this source code is governed by a BSD-style license that can be found | ||
// in the LICENSE file. | ||
|
||
package mysqlstore | ||
|
||
import ( | ||
"database/sql" | ||
"fmt" | ||
|
||
"github.com/clevergo/captchas/dbstore" | ||
) | ||
|
||
type Store struct { | ||
*dbstore.Store | ||
} | ||
|
||
func New(db *sql.DB, opts ...dbstore.Option) *Store { | ||
return &Store{dbstore.New(db, &dialect{}, opts...)} | ||
} | ||
|
||
type dialect struct { | ||
} | ||
|
||
func (d *dialect) Insert(table string) string { | ||
return fmt.Sprintf(`INSERT INTO %s(id, answer, created_at, expires_in) VALUES(?, ?, ?, ?)`, table) | ||
} | ||
|
||
func (d *dialect) QueryRow(table string) string { | ||
return fmt.Sprintf(`SELECT id, answer, expires_in FROM %s WHERE id = ?`, table) | ||
} | ||
|
||
func (d *dialect) Delete(table string) string { | ||
return fmt.Sprintf(`DELETE FROM %s WHERE id=?`, table) | ||
} | ||
|
||
func (d *dialect) DeleteExpired(table string) string { | ||
return fmt.Sprintf(`DELETE FROM %s WHERE expires_in<?`, table) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,3 @@ | ||
module github.com/clevergo/captchas/postgresstore | ||
|
||
go 1.14 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,39 @@ | ||
// Copyright 2020 CleverGo. All rights reserved. | ||
// Use of this source code is governed by a BSD-style license that can be found | ||
// in the LICENSE file. | ||
|
||
package postgresstore | ||
|
||
import ( | ||
"database/sql" | ||
"fmt" | ||
|
||
"github.com/clevergo/captchas/dbstore" | ||
) | ||
|
||
type Store struct { | ||
*dbstore.Store | ||
} | ||
|
||
func New(db *sql.DB, opts ...dbstore.Option) *Store { | ||
return &Store{dbstore.New(db, &dialect{}, opts...)} | ||
} | ||
|
||
type dialect struct { | ||
} | ||
|
||
func (d *dialect) Insert(table string) string { | ||
return fmt.Sprintf(`INSERT INTO %s(id, answer, created_at, expires_in) VALUES($1, $2, $3, $4)`, table) | ||
} | ||
|
||
func (d *dialect) QueryRow(table string) string { | ||
return fmt.Sprintf(`SELECT id, answer, expires_in FROM %s WHERE id = $1`, table) | ||
} | ||
|
||
func (d *dialect) Delete(table string) string { | ||
return fmt.Sprintf(`DELETE FROM %s WHERE id=$1`, table) | ||
} | ||
|
||
func (d *dialect) DeleteExpired(table string) string { | ||
return fmt.Sprintf(`DELETE FROM %s WHERE expires_in<$1`, table) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,3 @@ | ||
module github.com/clevergo/captchas/sqlite3store | ||
|
||
go 1.14 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,39 @@ | ||
// Copyright 2020 CleverGo. All rights reserved. | ||
// Use of this source code is governed by a BSD-style license that can be found | ||
// in the LICENSE file. | ||
|
||
package sqlite3store | ||
|
||
import ( | ||
"database/sql" | ||
"fmt" | ||
|
||
"github.com/clevergo/captchas/dbstore" | ||
) | ||
|
||
type Store struct { | ||
*dbstore.Store | ||
} | ||
|
||
func New(db *sql.DB, opts ...dbstore.Option) *Store { | ||
return &Store{dbstore.New(db, &dialect{}, opts...)} | ||
} | ||
|
||
type dialect struct { | ||
} | ||
|
||
func (d *dialect) Insert(table string) string { | ||
return fmt.Sprintf(`INSERT INTO %s(id, answer, created_at, expires_in) VALUES(?, ?, ?, ?)`, table) | ||
} | ||
|
||
func (d *dialect) QueryRow(table string) string { | ||
return fmt.Sprintf(`SELECT id, answer, expires_in FROM %s WHERE id = ?`, table) | ||
} | ||
|
||
func (d *dialect) Delete(table string) string { | ||
return fmt.Sprintf(`DELETE FROM %s WHERE id=?`, table) | ||
} | ||
|
||
func (d *dialect) DeleteExpired(table string) string { | ||
return fmt.Sprintf(`DELETE FROM %s WHERE expires_in<?`, table) | ||
} |