mirror of
https://github.com/ChronosX88/yans.git
synced 2024-11-23 12:02:19 +00:00
Make the storage backend modular
This commit is contained in:
parent
99061051e7
commit
3933abd40b
@ -30,11 +30,11 @@ func main() {
|
||||
log.Printf("Starting %s...", common.ServerName)
|
||||
ns, err := server.NewNNTPServer(cfg)
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
log.Fatalf("Error occurred while starting the server: %s", err)
|
||||
}
|
||||
|
||||
if err := ns.Start(); err != nil {
|
||||
log.Fatal(err)
|
||||
log.Fatalf("Error occurred while starting the server: %s", err)
|
||||
}
|
||||
log.Printf("%s has been successfully started!", common.ServerName)
|
||||
log.Printf("Version: %s", common.ServerVersion)
|
||||
|
6
config.sample.toml
Normal file
6
config.sample.toml
Normal file
@ -0,0 +1,6 @@
|
||||
address = "localhost"
|
||||
port = 1119
|
||||
backend_type = "sqlite"
|
||||
|
||||
[sqlite]
|
||||
path = "yans.db"
|
47
internal/backend/sqlite/sqlite.go
Normal file
47
internal/backend/sqlite/sqlite.go
Normal file
@ -0,0 +1,47 @@
|
||||
package sqlite
|
||||
|
||||
import (
|
||||
"embed"
|
||||
"github.com/ChronosX88/yans/internal/config"
|
||||
"github.com/ChronosX88/yans/internal/models"
|
||||
"github.com/jmoiron/sqlx"
|
||||
_ "github.com/mattn/go-sqlite3"
|
||||
"github.com/pressly/goose/v3"
|
||||
)
|
||||
|
||||
//go:embed migrations/*.sql
|
||||
var migrations embed.FS
|
||||
|
||||
type SQLiteBackend struct {
|
||||
db *sqlx.DB
|
||||
}
|
||||
|
||||
func NewSQLiteBackend(cfg config.SQLiteBackendConfig) (*SQLiteBackend, error) {
|
||||
db, err := sqlx.Open("sqlite3", cfg.Path)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
goose.SetBaseFS(migrations)
|
||||
|
||||
if err := goose.SetDialect("sqlite3"); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if err := goose.Up(db.DB, "migrations"); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return &SQLiteBackend{
|
||||
db: db,
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (sb *SQLiteBackend) ListGroups() ([]models.Group, error) {
|
||||
var groups []models.Group
|
||||
return groups, sb.db.Select(&groups, "SELECT * FROM groups")
|
||||
}
|
||||
|
||||
func (sb *SQLiteBackend) GetArticlesCount(g models.Group) (int, error) {
|
||||
var count int
|
||||
return count, sb.db.Select(&count, "SELECT COUNT(*) FROM articles_to_groups WHERE group_id = ?", g.ID)
|
||||
}
|
12
internal/backend/storage_backend.go
Normal file
12
internal/backend/storage_backend.go
Normal file
@ -0,0 +1,12 @@
|
||||
package backend
|
||||
|
||||
import "github.com/ChronosX88/yans/internal/models"
|
||||
|
||||
const (
|
||||
SupportedBackendList = "sqlite"
|
||||
)
|
||||
|
||||
type StorageBackend interface {
|
||||
ListGroups() ([]models.Group, error)
|
||||
GetArticlesCount(g models.Group) (int, error)
|
||||
}
|
@ -5,9 +5,19 @@ import (
|
||||
"os"
|
||||
)
|
||||
|
||||
const (
|
||||
SQLiteBackendType = "sqlite"
|
||||
)
|
||||
|
||||
type Config struct {
|
||||
Port int
|
||||
DatabasePath string
|
||||
Address string `toml:"address"`
|
||||
Port int `toml:"port"`
|
||||
BackendType string `toml:"backend_type"`
|
||||
SQLite SQLiteBackendConfig `toml:"sqlite"`
|
||||
}
|
||||
|
||||
type SQLiteBackendConfig struct {
|
||||
Path string `toml:"path"`
|
||||
}
|
||||
|
||||
func ParseConfig(path string) (Config, error) {
|
||||
|
@ -1,6 +0,0 @@
|
||||
package internal
|
||||
|
||||
import "embed"
|
||||
|
||||
//go:embed migrations/*.sql
|
||||
var Migrations embed.FS
|
@ -2,21 +2,20 @@ package server
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/ChronosX88/yans/internal/models"
|
||||
"github.com/ChronosX88/yans/internal/backend"
|
||||
"github.com/ChronosX88/yans/internal/protocol"
|
||||
"github.com/jmoiron/sqlx"
|
||||
"strings"
|
||||
"time"
|
||||
)
|
||||
|
||||
type Handler struct {
|
||||
handlers map[string]func(s *Session, arguments []string) error
|
||||
db *sqlx.DB
|
||||
backend backend.StorageBackend
|
||||
}
|
||||
|
||||
func NewHandler(db *sqlx.DB) *Handler {
|
||||
func NewHandler(b backend.StorageBackend) *Handler {
|
||||
h := &Handler{}
|
||||
h.db = db
|
||||
h.backend = b
|
||||
h.handlers = map[string]func(s *Session, arguments []string) error{
|
||||
protocol.CommandCapabilities: h.handleCapabilities,
|
||||
protocol.CommandDate: h.handleDate,
|
||||
@ -54,7 +53,7 @@ func (h *Handler) handleList(s *Session, arguments []string) error {
|
||||
fallthrough
|
||||
case "ACTIVE":
|
||||
{
|
||||
groups, err := h.listGroups()
|
||||
groups, err := h.backend.ListGroups()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@ -66,7 +65,7 @@ func (h *Handler) handleList(s *Session, arguments []string) error {
|
||||
}
|
||||
case "NEWSGROUPS":
|
||||
{
|
||||
groups, err := h.listGroups()
|
||||
groups, err := h.backend.ListGroups()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@ -117,14 +116,3 @@ func (h *Handler) Handle(s *Session, message string) error {
|
||||
}
|
||||
return handler(s, splittedMessage[1:])
|
||||
}
|
||||
|
||||
// TODO Refactor to "storage backend" entity
|
||||
func (h *Handler) listGroups() ([]models.Group, error) {
|
||||
var groups []models.Group
|
||||
return groups, h.db.Select(&groups, "SELECT * FROM groups")
|
||||
}
|
||||
|
||||
func (h *Handler) getArticlesCount(g models.Group) (int, error) {
|
||||
var count int
|
||||
return count, h.db.Select(&count, "SELECT COUNT(*) FROM articles_to_groups WHERE group_id = ?", g.ID)
|
||||
}
|
||||
|
@ -3,14 +3,12 @@ package server
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"github.com/ChronosX88/yans/internal"
|
||||
"github.com/ChronosX88/yans/internal/backend"
|
||||
"github.com/ChronosX88/yans/internal/backend/sqlite"
|
||||
"github.com/ChronosX88/yans/internal/common"
|
||||
"github.com/ChronosX88/yans/internal/config"
|
||||
"github.com/ChronosX88/yans/internal/protocol"
|
||||
"github.com/google/uuid"
|
||||
"github.com/jmoiron/sqlx"
|
||||
_ "github.com/mattn/go-sqlite3"
|
||||
"github.com/pressly/goose/v3"
|
||||
"log"
|
||||
"net"
|
||||
"sync"
|
||||
@ -28,47 +26,61 @@ type NNTPServer struct {
|
||||
ctx context.Context
|
||||
cancelFunc context.CancelFunc
|
||||
|
||||
ln net.Listener
|
||||
port int
|
||||
ln net.Listener
|
||||
cfg config.Config
|
||||
|
||||
db *sqlx.DB
|
||||
backend backend.StorageBackend
|
||||
|
||||
sessionPool map[string]*Session
|
||||
sessionPoolMutex sync.Mutex
|
||||
}
|
||||
|
||||
func NewNNTPServer(cfg config.Config) (*NNTPServer, error) {
|
||||
db, err := sqlx.Open("sqlite3", cfg.DatabasePath)
|
||||
b, err := initBackend(cfg)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
goose.SetBaseFS(internal.Migrations)
|
||||
|
||||
if err := goose.SetDialect("sqlite3"); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if err := goose.Up(db.DB, "migrations"); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
ctx, cancel := context.WithCancel(context.Background())
|
||||
ns := &NNTPServer{
|
||||
ctx: ctx,
|
||||
cancelFunc: cancel,
|
||||
port: cfg.Port,
|
||||
db: db,
|
||||
cfg: cfg,
|
||||
backend: b,
|
||||
sessionPool: map[string]*Session{},
|
||||
}
|
||||
return ns, nil
|
||||
}
|
||||
|
||||
func initBackend(cfg config.Config) (backend.StorageBackend, error) {
|
||||
var sb backend.StorageBackend
|
||||
|
||||
switch cfg.BackendType {
|
||||
case config.SQLiteBackendType:
|
||||
{
|
||||
sqliteBackend, err := sqlite.NewSQLiteBackend(cfg.SQLite)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
sb = sqliteBackend
|
||||
}
|
||||
default:
|
||||
{
|
||||
return nil, fmt.Errorf("invalid backend type, supported backends: %s", backend.SupportedBackendList)
|
||||
}
|
||||
}
|
||||
return sb, nil
|
||||
}
|
||||
|
||||
func (ns *NNTPServer) Start() error {
|
||||
ln, err := net.Listen("tcp", fmt.Sprintf(":%d", ns.port))
|
||||
address := fmt.Sprintf("%s:%d", ns.cfg.Address, ns.cfg.Port)
|
||||
ln, err := net.Listen("tcp", address)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
log.Printf("Listening on %s...", address)
|
||||
|
||||
go func(ctx context.Context) {
|
||||
for {
|
||||
select {
|
||||
@ -84,7 +96,7 @@ func (ns *NNTPServer) Start() error {
|
||||
|
||||
id, _ := uuid.NewUUID()
|
||||
closed := make(chan bool)
|
||||
session, err := NewSession(ctx, conn, Capabilities, id.String(), closed, NewHandler(ns.db))
|
||||
session, err := NewSession(ctx, conn, Capabilities, id.String(), closed, NewHandler(ns.backend))
|
||||
ns.sessionPoolMutex.Lock()
|
||||
ns.sessionPool[id.String()] = session
|
||||
ns.sessionPoolMutex.Unlock()
|
||||
|
Loading…
Reference in New Issue
Block a user