Change db column name. Track missing file with git

This commit is contained in:
leafee98 2023-02-15 12:09:09 +08:00
parent c98e061d2e
commit 80bb2cffc2
8 changed files with 156 additions and 35 deletions

34
cmd/paste-abroad/main.go Normal file
View file

@ -0,0 +1,34 @@
package main
import (
limit "github.com/gin-contrib/size"
"github.com/gin-gonic/gin"
"github.com/leafee98/paste-abroad/internel/router"
"github.com/leafee98/paste-abroad/internel/config"
"github.com/leafee98/paste-abroad/internel/storage/sqlite"
"fmt"
)
func main() {
c, err := config.Load("./config.toml")
if err != nil {
fmt.Printf("Error when loading config: %v", err)
return
}
store, err := sqlite.New(c.DBString, c.IdLength)
if err != nil {
fmt.Println(err)
}
r := gin.Default()
r.Use(limit.RequestSizeLimiter(c.MaxPasteSize))
router.Init(r, store, c.DefaultLifetime)
r.Run(":8081")
}

27
go.mod
View file

@ -3,14 +3,29 @@ module github.com/leafee98/paste-abroad
go 1.19
require (
github.com/fasthttp/router v1.4.14
github.com/BurntSushi/toml v1.2.1
github.com/gin-contrib/size v0.0.0-20230212012657-e14a14094dc4
github.com/gin-gonic/gin v1.8.2
github.com/mattn/go-sqlite3 v1.14.16
github.com/valyala/fasthttp v1.44.0
)
require (
github.com/andybalholm/brotli v1.0.4 // indirect
github.com/klauspost/compress v1.15.9 // indirect
github.com/savsgio/gotils v0.0.0-20220530130905-52f3993e8d6d // indirect
github.com/valyala/bytebufferpool v1.0.0 // indirect
github.com/gin-contrib/sse v0.1.0 // indirect
github.com/go-playground/locales v0.14.0 // indirect
github.com/go-playground/universal-translator v0.18.0 // indirect
github.com/go-playground/validator/v10 v10.11.1 // indirect
github.com/goccy/go-json v0.9.11 // indirect
github.com/json-iterator/go v1.1.12 // indirect
github.com/leodido/go-urn v1.2.1 // indirect
github.com/mattn/go-isatty v0.0.16 // indirect
github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421 // indirect
github.com/modern-go/reflect2 v1.0.2 // indirect
github.com/pelletier/go-toml/v2 v2.0.6 // indirect
github.com/ugorji/go/codec v1.2.7 // indirect
golang.org/x/crypto v0.0.0-20220214200702-86341886e292 // indirect
golang.org/x/net v0.4.0 // indirect
golang.org/x/sys v0.3.0 // indirect
golang.org/x/text v0.5.0 // indirect
google.golang.org/protobuf v1.28.1 // indirect
gopkg.in/yaml.v2 v2.4.0 // indirect
)

28
internel/config/config.go Normal file
View file

@ -0,0 +1,28 @@
package config
import (
"github.com/BurntSushi/toml"
"os"
)
type Config struct {
DefaultLifetime int64 `toml:"lifetime"`
IdLength int `toml:"id_length"`
Database string `toml:"database"`
DBString string `toml:"db_string"`
MaxPasteSize int64 `toml:"max_paste_size"`
}
func Load(path string) (*Config, error) {
buffer, err := os.ReadFile(path)
if err != nil {
return nil, err
}
config_content := string(buffer)
var c Config
toml.Decode(config_content, &c)
return &c, nil
}

View file

@ -13,16 +13,15 @@ import (
var store storage.Storage
var expireTime int64
var defaultExpireTime int64
func New(s storage.Storage, expireTime int) *gin.Engine {
func Init(e *gin.Engine, s storage.Storage, expireTime int64) {
defaultExpireTime = expireTime
store = s
var r = gin.Default()
r.POST("/", PostPaste)
r.GET("/raw/:id", GetPasteRaw)
r.GET("/:id", GetPaste)
return r
e.POST("/", PostPaste)
e.GET("/raw/:id", GetPasteRaw)
e.GET("/:id", GetPaste)
}
// PostPaste require two parameters from either URL or form-data
@ -42,10 +41,20 @@ func PostPaste(ctx *gin.Context) {
content_buffer.ReadFrom(c_reader)
content = content_buffer.Bytes()
} else {
content = []byte(requestValue(ctx, "c", false))
content_str, exists := getRequestValue(ctx, "c", false)
if !exists {
ctx.String(400, "cannot get paste content: missing parameter \"c\"")
return
}
content = []byte(content_str)
}
case "application/x-www-form-urlencoded":
content = []byte(requestValue(ctx, "c", false))
content_str, exists := getRequestValue(ctx, "c", false)
if !exists {
ctx.String(400, "cannot get paste content: missing parameter \"c\"")
return
}
content = []byte(content_str)
default:
ctx.String(400, "unrecognized content type: %s", ctx.ContentType())
return
@ -56,13 +65,13 @@ func PostPaste(ctx *gin.Context) {
life_int, err := strconv.ParseInt(life, 10, 64)
if err != nil {
life_int = expireTime
life_int = defaultExpireTime
}
paste := storage.Paste{
Content: content,
// Content: content_buffer.Bytes(),
Plain: !isEncrypt(encrypt),
Encrypt: isEncrypt(encrypt),
Expire: life_int * 1000 * 3600 * 24 + time.Now().UnixMilli(),
}
@ -73,7 +82,7 @@ func PostPaste(ctx *gin.Context) {
return
}
log.Printf("Saved a paste { id: %s, plain: %t, expire: %d}", id, paste.Plain, paste.Expire)
log.Printf("Saved a paste { id: %s, encrypt: %t, expire: %d}", id, paste.Encrypt, paste.Expire)
ctx.String(200, id)
}
@ -93,10 +102,10 @@ func GetPasteRaw(ctx * gin.Context) {
return
}
if content.Plain {
ctx.Data(200, "text/plain", content.Content)
} else {
if content.Encrypt {
ctx.Data(200, "application/octet-stream", content.Content)
} else {
ctx.Data(200, "text/plain", content.Content)
}
}
@ -121,6 +130,25 @@ func requestValue(ctx *gin.Context, key string, urlPrefer bool) string {
return value
}
func getRequestValue(ctx *gin.Context, key string, urlPrefer bool) (string, bool) {
var value string
var exists bool
if urlPrefer {
value, exists = ctx.GetQuery(key)
if !exists {
value, exists = ctx.GetPostForm(key)
}
} else {
value, exists = ctx.GetPostForm(key)
if !exists {
value, exists = ctx.GetQuery(key)
}
}
return value, exists
}
func isEncrypt(s string) bool {
ture_values := []string{ "t", "true", "y", "yes", "1" }

View file

@ -39,7 +39,7 @@ func initDatabase(db *sql.DB) error {
create table if not exists paste (
id text unique,
content blob,
plain integer,
encrypt integer,
expire integer
);
@ -62,22 +62,22 @@ func (s *StorageSqlite) Close() error {
}
func (s *StorageSqlite) Save(p *storage.Paste) (string, error) {
stmt, err := s.db.Prepare(`insert into paste (id, content, plain, expire) values (?, ?, ?, ?);`)
stmt, err := s.db.Prepare(`insert into paste (id, content, encrypt, expire) values (?, ?, ?, ?);`)
if err != nil {
return "", err
}
defer stmt.Close()
var id string
var plain = 0
var encrypt = 0
if p.Plain {
plain = 1
if p.Encrypt {
encrypt = 1
}
for true {
id = utils.GenerateId(s.idLength)
_, err = stmt.Exec(id, p.Content, plain, p.Expire)
_, err = stmt.Exec(id, p.Content, encrypt, p.Expire)
if err == nil {
break
} else if errors.Is(err, sqlite3.ErrConstraint) {
@ -91,7 +91,7 @@ func (s *StorageSqlite) Save(p *storage.Paste) (string, error) {
}
func (s *StorageSqlite) Get(id string) (*storage.Paste, error) {
stmt, err := s.db.Prepare(`select content, plain, expire from paste where id = ?`)
stmt, err := s.db.Prepare(`select content, encrypt, expire from paste where id = ?`)
if err != nil {
return nil, err
}
@ -108,14 +108,14 @@ func (s *StorageSqlite) Get(id string) (*storage.Paste, error) {
}
defer rows.Close()
var plain = 0
var encrypt = 0
if err = rows.Scan(&p.Content, &plain, &p.Expire); err != nil {
if err = rows.Scan(&p.Content, &encrypt, &p.Expire); err != nil {
return nil, err
}
if plain != 0 {
p.Plain = true
if encrypt != 0 {
p.Encrypt = true
}
return &p, nil

View file

@ -35,12 +35,12 @@ func TestSqlite(t * testing.T) {
func testGetSave(s *sqlite.StorageSqlite, t * testing.T) {
var a = storage.Paste {
Content: []byte("abc"),
Plain: true,
Encrypt: false,
Expire: time.Now().UnixMilli() + 15 * 1000,
}
var b = storage.Paste {
Content: []byte("def"),
Plain: true,
Encrypt: false,
Expire: time.Now().UnixMilli() - 15 * 1000,
}

View file

@ -7,7 +7,7 @@ type Storage interface {
}
type Paste struct {
Plain bool
Encrypt bool
Content []byte
Expire int64
}

16
internel/utils/utils.go Normal file
View file

@ -0,0 +1,16 @@
package utils
import (
"math/rand"
)
var letters = []rune("abcdefghijklmnopqrstuvwxyz")
// GenearteId will create a string contains 8 lowercase alphabets
func GenerateId(length int) string {
buffer := make([]rune, length)
for i := range buffer {
buffer[i] = letters[rand.Intn(len(letters))]
}
return string(buffer)
}