forked from jriou/coller
feat: Use snowflake identifiers
Fixes #29. Signed-off-by: Julien Riou <julien@riou.xyz>
This commit is contained in:
parent
d26879a333
commit
2c3ca08dbf
9 changed files with 24 additions and 39 deletions
|
@ -13,9 +13,10 @@ import (
|
|||
"path/filepath"
|
||||
"syscall"
|
||||
|
||||
"git.riou.xyz/jriou/coller/internal"
|
||||
"golang.design/x/clipboard"
|
||||
"golang.org/x/term"
|
||||
|
||||
"git.riou.xyz/jriou/coller/internal"
|
||||
)
|
||||
|
||||
var (
|
||||
|
|
|
@ -18,7 +18,7 @@ The file format is **JSON**:
|
|||
* **title** (string): Title of the website
|
||||
* **database_type** (string): Type of the database (default "sqlite", "postgres" also supported)
|
||||
* **database_dsn** (string): Connection string for the database (default "collerd.db")
|
||||
* **id_length** (int): Number of characters for note identifiers (default 5)
|
||||
* **node_id** (int): Number between 0 and 1023 to define the node generating identifiers (see [snowflake](https://github.com/bwmarrin/snowflake))
|
||||
* **password_length** (int): Number of characters for generated passwords (default 16)
|
||||
* **expiration_interval** (int): Number of seconds to wait between two expiration runs
|
||||
* **listen_address** (string): Address to listen for the web server (default "0.0.0.0")
|
||||
|
|
|
@ -5,9 +5,10 @@ import (
|
|||
"log/slog"
|
||||
"os"
|
||||
|
||||
"github.com/prometheus/client_golang/prometheus"
|
||||
|
||||
"git.riou.xyz/jriou/coller/internal"
|
||||
"git.riou.xyz/jriou/coller/server"
|
||||
"github.com/prometheus/client_golang/prometheus"
|
||||
)
|
||||
|
||||
var (
|
||||
|
@ -69,7 +70,6 @@ func handleMain() int {
|
|||
return internal.ReturnError(logger, "could not create server", err)
|
||||
}
|
||||
|
||||
srv.SetIDLength(config.IDLength)
|
||||
srv.SetPasswordLength(config.PasswordLength)
|
||||
|
||||
if config.EnableMetrics {
|
||||
|
|
|
@ -17,6 +17,7 @@ require (
|
|||
|
||||
require (
|
||||
github.com/beorn7/perks v1.0.1 // indirect
|
||||
github.com/bwmarrin/snowflake v0.3.0 // indirect
|
||||
github.com/cespare/xxhash/v2 v2.3.0 // indirect
|
||||
github.com/jackc/pgpassfile v1.0.0 // indirect
|
||||
github.com/jackc/pgservicefile v0.0.0-20240606120523-5a60cdf6a761 // indirect
|
||||
|
|
|
@ -1,5 +1,7 @@
|
|||
github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM=
|
||||
github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw=
|
||||
github.com/bwmarrin/snowflake v0.3.0 h1:xm67bEhkKh6ij1790JB83OujPR5CzNe8QuQqAgISZN0=
|
||||
github.com/bwmarrin/snowflake v0.3.0/go.mod h1:NdZxfVWX+oR6y2K0o6qAYv6gIOP9rjG0/E9WsDpxqwE=
|
||||
github.com/cespare/xxhash/v2 v2.3.0 h1:UL815xU9SqsFlibzuggzjXhog7bL6oX9BbNZnL2UFvs=
|
||||
github.com/cespare/xxhash/v2 v2.3.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
|
||||
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
|
|
|
@ -10,7 +10,7 @@ type Config struct {
|
|||
Title string `json:"title"`
|
||||
DatabaseType string `json:"database_type"`
|
||||
DatabaseDsn string `json:"database_dsn"`
|
||||
IDLength int `json:"id_length"`
|
||||
NodeID int64 `json:"node_id"`
|
||||
PasswordLength int `json:"password_length"`
|
||||
ExpirationInterval int `json:"expiration_interval"`
|
||||
ListenAddress string `json:"listen_address"`
|
||||
|
@ -36,7 +36,7 @@ func NewConfig() *Config {
|
|||
Title: "Coller",
|
||||
DatabaseType: "sqlite",
|
||||
DatabaseDsn: "collerd.db",
|
||||
IDLength: 5,
|
||||
NodeID: 1,
|
||||
PasswordLength: 16,
|
||||
ExpirationInterval: 60, // 1 minute
|
||||
ListenAddress: "0.0.0.0",
|
||||
|
@ -88,8 +88,8 @@ func (c *Config) Check() error {
|
|||
}
|
||||
}
|
||||
|
||||
if c.IDLength <= 0 {
|
||||
return fmt.Errorf("identifiers length must be greater than zero")
|
||||
if c.NodeID < 0 || c.NodeID > 1023 {
|
||||
return fmt.Errorf("node id must be between 0 and 1023")
|
||||
}
|
||||
|
||||
if c.PasswordLength < internal.MIN_PASSWORD_LENGTH || c.PasswordLength > internal.MAX_PASSWORD_LENGTH {
|
||||
|
|
|
@ -7,11 +7,13 @@ import (
|
|||
"strings"
|
||||
"time"
|
||||
|
||||
"git.riou.xyz/jriou/coller/internal"
|
||||
"github.com/bwmarrin/snowflake"
|
||||
"gorm.io/driver/postgres"
|
||||
"gorm.io/driver/sqlite"
|
||||
"gorm.io/gorm"
|
||||
"gorm.io/gorm/logger"
|
||||
|
||||
"git.riou.xyz/jriou/coller/internal"
|
||||
)
|
||||
|
||||
type Database struct {
|
||||
|
@ -22,6 +24,7 @@ type Database struct {
|
|||
expiration int
|
||||
languages []string
|
||||
language string
|
||||
node *snowflake.Node
|
||||
}
|
||||
|
||||
var gconfig = &gorm.Config{
|
||||
|
@ -48,6 +51,11 @@ func NewDatabase(logger *slog.Logger, config *Config) (d *Database, err error) {
|
|||
|
||||
logger.Debug("connected to the database")
|
||||
|
||||
node, err := snowflake.NewNode(config.NodeID)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
d = &Database{
|
||||
logger: l,
|
||||
db: db,
|
||||
|
@ -56,6 +64,7 @@ func NewDatabase(logger *slog.Logger, config *Config) (d *Database, err error) {
|
|||
expiration: config.Expiration,
|
||||
languages: internal.ToLowerStringSlice(config.Languages),
|
||||
language: strings.ToLower(config.Language),
|
||||
node: node,
|
||||
}
|
||||
|
||||
if err = d.UpdateSchema(); err != nil {
|
||||
|
@ -132,6 +141,7 @@ func (d *Database) Create(content []byte, password string, encrypted bool, expir
|
|||
}
|
||||
|
||||
note = &Note{
|
||||
ID: d.node.Generate().String(),
|
||||
Content: content,
|
||||
ExpiresAt: time.Now().Add(time.Duration(expiration) * time.Second),
|
||||
Encrypted: encrypted,
|
||||
|
|
|
@ -1,17 +1,11 @@
|
|||
package server
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"time"
|
||||
|
||||
"git.riou.xyz/jriou/coller/internal"
|
||||
"gorm.io/gorm"
|
||||
)
|
||||
|
||||
const ID_MAX_RETRIES = 10
|
||||
|
||||
var idLength = 5
|
||||
|
||||
type Note struct {
|
||||
ID string `json:"id" gorm:"primaryKey"`
|
||||
Content []byte `json:"content" gorm:"not null"`
|
||||
|
@ -21,27 +15,8 @@ type Note struct {
|
|||
Language string `json:"language"`
|
||||
}
|
||||
|
||||
// Generate ID and compress content before saving to the database
|
||||
// Compress content before saving to the database
|
||||
func (n *Note) BeforeCreate(trx *gorm.DB) (err error) {
|
||||
for i := 0; i < ID_MAX_RETRIES; i++ {
|
||||
if n.ID != "" {
|
||||
continue
|
||||
}
|
||||
|
||||
id := internal.GenerateChars(idLength)
|
||||
|
||||
var note Note
|
||||
trx.Where("id = ?", id).Find(¬e)
|
||||
|
||||
if note.ID == "" {
|
||||
n.ID = id
|
||||
continue
|
||||
}
|
||||
}
|
||||
if n.ID == "" {
|
||||
return fmt.Errorf("could not find unique id before creating the note")
|
||||
}
|
||||
|
||||
n.Content = Compress(n.Content)
|
||||
return nil
|
||||
}
|
||||
|
|
|
@ -41,10 +41,6 @@ func NewServer(logger *slog.Logger, db *Database, config *Config, version string
|
|||
}, nil
|
||||
}
|
||||
|
||||
func (s *Server) SetIDLength(length int) {
|
||||
idLength = length
|
||||
}
|
||||
|
||||
func (s *Server) SetPasswordLength(length int) {
|
||||
passwordLength = length
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue