Implementa sistema de IDs curtos para pastes, substituindo hashes SHA-256. Atualiza a estrutura do banco de dados e a lógica de inserção para suportar a detecção de duplicatas. O README e a documentação de migração foram atualizados para refletir essas mudanças.

This commit is contained in:
Luiz Costa
2025-08-29 08:57:44 -03:00
parent 9abff0338b
commit 18c4b0613f
8 changed files with 334 additions and 47 deletions
+71 -6
View File
@@ -7,6 +7,7 @@ import (
"flag"
"fmt"
"log"
"math/rand"
"os"
"time"
@@ -16,7 +17,41 @@ import (
_ "modernc.org/sqlite"
)
const shortIDLength = 7
// generateShortID gera um ID único de 7 caracteres
func generateShortID() string {
const charset = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789"
b := make([]byte, shortIDLength)
for i := range b {
b[i] = charset[rand.Intn(len(charset))]
}
return string(b)
}
// generateUniqueShortID gera um ID único que não existe no banco
func generateUniqueShortID(db *sql.DB) (string, error) {
maxAttempts := 100
for i := 0; i < maxAttempts; i++ {
id := generateShortID()
// Verificar se o ID já existe
var exists int
err := db.QueryRow("SELECT 1 FROM pastes WHERE short_id = ? LIMIT 1", id).Scan(&exists)
if err == sql.ErrNoRows {
return id, nil
}
if err != nil {
return "", err
}
}
return "", fmt.Errorf("não foi possível gerar um ID único após %d tentativas", maxAttempts)
}
func main() {
// Initialize random seed
rand.Seed(time.Now().UnixNano())
var boltPath, sqlitePath string
flag.StringVar(&boltPath, "bolt", "", "caminho para o arquivo BoltDB")
flag.StringVar(&sqlitePath, "sqlite", "", "caminho para o arquivo SQLite3 de destino")
@@ -44,8 +79,9 @@ func main() {
// Criar tabela no SQLite3
_, err = sqliteDB.Exec(`
CREATE TABLE IF NOT EXISTS pastes (
hash TEXT PRIMARY KEY,
short_id TEXT PRIMARY KEY,
content TEXT NOT NULL,
content_hash TEXT NOT NULL,
created_at INTEGER NOT NULL
)
`)
@@ -53,6 +89,17 @@ func main() {
log.Fatal("Erro ao criar tabela:", err)
}
// Criar índices
_, err = sqliteDB.Exec(`CREATE INDEX IF NOT EXISTS idx_pastes_content_hash ON pastes(content_hash)`)
if err != nil {
log.Fatal("Erro ao criar índice content_hash:", err)
}
_, err = sqliteDB.Exec(`CREATE INDEX IF NOT EXISTS idx_pastes_created_at ON pastes(created_at)`)
if err != nil {
log.Fatal("Erro ao criar índice created_at:", err)
}
// Iniciar transação no SQLite3
tx, err := sqliteDB.Begin()
if err != nil {
@@ -60,7 +107,7 @@ func main() {
}
// Preparar statement de inserção
stmt, err := tx.Prepare("INSERT OR IGNORE INTO pastes (hash, content, created_at) VALUES (?, ?, ?)")
stmt, err := tx.Prepare("INSERT OR IGNORE INTO pastes (short_id, content, content_hash, created_at) VALUES (?, ?, ?, ?)")
if err != nil {
log.Fatal("Erro ao preparar statement:", err)
}
@@ -68,6 +115,7 @@ func main() {
// Migrar dados do BoltDB para SQLite3
count := 0
duplicates := 0
err = boltDB.View(func(tx *bolt.Tx) error {
b := tx.Bucket([]byte("pastes"))
if b == nil {
@@ -79,10 +127,27 @@ func main() {
hash := sha256.Sum256(v)
hashStr := hex.EncodeToString(hash[:])
// Inserir no SQLite3
_, err := stmt.Exec(hashStr, string(v), time.Now().Unix())
// Verificar se já existe um paste com o mesmo conteúdo
var existingID string
err := sqliteDB.QueryRow("SELECT short_id FROM pastes WHERE content_hash = ? LIMIT 1", hashStr).Scan(&existingID)
if err == nil {
// Paste já existe, pular
duplicates++
return nil
} else if err != sql.ErrNoRows {
return fmt.Errorf("erro ao verificar duplicata: %v", err)
}
// Gerar ID curto único
shortID, err := generateUniqueShortID(sqliteDB)
if err != nil {
return fmt.Errorf("erro ao inserir paste %s: %v", hashStr, err)
return fmt.Errorf("erro ao gerar ID único: %v", err)
}
// Inserir no SQLite3
_, err = stmt.Exec(shortID, string(v), hashStr, time.Now().Unix())
if err != nil {
return fmt.Errorf("erro ao inserir paste %s: %v", shortID, err)
}
count++
@@ -105,5 +170,5 @@ func main() {
log.Fatal("Erro ao fazer commit:", err)
}
fmt.Printf("Migração concluída! %d pastes migrados com sucesso.\n", count)
fmt.Printf("Migração concluída! %d pastes migrados com sucesso, %d duplicatas ignoradas.\n", count, duplicates)
}