integrate web and mail server

now, there is only one binary that starts both servers,
making them use the same SQL connection.

this commit also added some `defer tx.Commit()` to ensure
all the transactions were closed
This commit is contained in:
Guilherme Rugai Freire 2024-07-10 16:56:46 -03:00
parent 52b3fa61ca
commit 48e7b5a9a5
No known key found for this signature in database
GPG Key ID: AC1D9B6E48E16AC1
10 changed files with 65 additions and 36 deletions

View File

@ -1,8 +1,4 @@
all: mail web all:
mail:
go build -o "./bin/$@_server" "./cmd/mail_server"
web:
templ generate templ generate
go build -o "./bin/$@_server" "./cmd/web_server" go build -o ./bin/server ./cmd/server

34
cmd/server/main.go Normal file
View File

@ -0,0 +1,34 @@
package main
import (
"database/sql"
"github.com/GRFreire/nthmail/pkg/mail_server"
"github.com/GRFreire/nthmail/pkg/web_server"
"log"
"sync"
_ "github.com/mattn/go-sqlite3"
)
func main() {
db, err := sql.Open("sqlite3", "./db.db")
if err != nil {
log.Fatal(err)
}
defer db.Close()
var wg sync.WaitGroup
wg.Add(1)
go func(db *sql.DB) {
defer wg.Done()
mail_server.Start(db)
}(db)
wg.Add(1)
go func(db *sql.DB) {
defer wg.Done()
web_server.Start(db)
}(db)
wg.Wait()
}

View File

@ -1,7 +1,8 @@
package main package mail_server
import ( import (
"database/sql" "database/sql"
"errors"
"fmt" "fmt"
"io" "io"
"log" "log"
@ -52,6 +53,7 @@ func (session *Session) Rcpt(to string, opts *smtp.RcptOptions) error {
} }
func (session *Session) Data(reader io.Reader) error { func (session *Session) Data(reader io.Reader) error {
defer session.tx.Rollback()
if bytes, err := io.ReadAll(reader); err != nil { if bytes, err := io.ReadAll(reader); err != nil {
return err return err
} else { } else {
@ -85,13 +87,7 @@ func (session *Session) Logout() error {
return nil return nil
} }
func main() { func Start(db *sql.DB) error {
db, err := sql.Open("sqlite3", "./db.db")
if err != nil {
log.Fatal(err)
}
defer db.Close()
backend := &Backend{ backend := &Backend{
db: db, db: db,
} }
@ -104,11 +100,12 @@ func main() {
} }
var port int var port int
var err error
port_str, exists := os.LookupEnv("MAIL_SERVER_PORT") port_str, exists := os.LookupEnv("MAIL_SERVER_PORT")
if exists { if exists {
port, err = strconv.Atoi(port_str) port, err = strconv.Atoi(port_str)
if err != nil { if err != nil {
log.Fatal("env:MAIL_SERVER_PORT is not a number") return errors.New("env:MAIL_SERVER_PORT is not a number")
} }
} else { } else {
port = 1025 port = 1025
@ -124,6 +121,8 @@ func main() {
log.Println("Starting server at", server.Addr) log.Println("Starting server at", server.Addr)
if err := server.ListenAndServe(); err != nil { if err := server.ListenAndServe(); err != nil {
log.Fatal(err) return err
} }
return nil
} }

View File

@ -1,4 +1,4 @@
package main package web_server
templ header(rcpt_addr string) { templ header(rcpt_addr string) {
<div class="header"> <div class="header">

View File

@ -1,4 +1,4 @@
package main package web_server
import ( import (
"fmt" "fmt"

View File

@ -1,4 +1,4 @@
package main package web_server
templ index_page() { templ index_page() {
<!DOCTYPE html> <!DOCTYPE html>

View File

@ -1,4 +1,4 @@
package main package web_server
import ( import (
"github.com/russross/blackfriday/v2" "github.com/russross/blackfriday/v2"

View File

@ -1,7 +1,8 @@
package main package web_server
import ( import (
"database/sql" "database/sql"
"errors"
"fmt" "fmt"
"log" "log"
"net/http" "net/http"
@ -15,15 +16,9 @@ import (
_ "github.com/mattn/go-sqlite3" _ "github.com/mattn/go-sqlite3"
) )
func main() { func Start(db *sql.DB) error {
server := &ServerResouces{} server := &ServerResouces{}
server.db = db
db, err := sql.Open("sqlite3", "./db.db")
if err != nil {
log.Fatal(err)
}
server.db = db
defer db.Close()
domain, exists := os.LookupEnv("MAIL_SERVER_DOMAIN") domain, exists := os.LookupEnv("MAIL_SERVER_DOMAIN")
if !exists { if !exists {
@ -32,11 +27,12 @@ func main() {
server.domain = domain server.domain = domain
var port int var port int
var err error
port_str, exists := os.LookupEnv("WEB_SERVER_PORT") port_str, exists := os.LookupEnv("WEB_SERVER_PORT")
if exists { if exists {
port, err = strconv.Atoi(port_str) port, err = strconv.Atoi(port_str)
if err != nil { if err != nil {
log.Fatal("env:MAIL_SERVER_PORT is not a number") return errors.New("env:WEB_SERVER_PORT is not a number")
} }
} else { } else {
port = 3000 port = 3000
@ -47,8 +43,10 @@ func main() {
log.Println("Listening on port", port) log.Println("Listening on port", port)
err = http.ListenAndServe(fmt.Sprintf(":%d", port), router) err = http.ListenAndServe(fmt.Sprintf(":%d", port), router)
if err != nil { if err != nil {
log.Fatal(err) return err
} }
return nil
} }
type ServerResouces struct { type ServerResouces struct {
@ -100,6 +98,7 @@ func (sr ServerResouces) handleInbox(res http.ResponseWriter, req *http.Request)
log.Println("could not begin db transaction") log.Println("could not begin db transaction")
return return
} }
defer tx.Commit()
stmt, err := tx.Prepare("SELECT mails.id, mails.arrived_at, mails.rcpt_addr, mails.from_addr, mails.data FROM mails WHERE mails.rcpt_addr = ?") stmt, err := tx.Prepare("SELECT mails.id, mails.arrived_at, mails.rcpt_addr, mails.from_addr, mails.data FROM mails WHERE mails.rcpt_addr = ?")
if err != nil { if err != nil {
@ -175,6 +174,7 @@ func (sr ServerResouces) handleMail(res http.ResponseWriter, req *http.Request)
log.Println("could not begin db transaction") log.Println("could not begin db transaction")
return return
} }
defer tx.Commit()
stmt, err := tx.Prepare("SELECT mails.id, mails.arrived_at, mails.rcpt_addr, mails.from_addr, mails.data FROM mails WHERE mails.rcpt_addr = ? AND mails.id = ?") stmt, err := tx.Prepare("SELECT mails.id, mails.arrived_at, mails.rcpt_addr, mails.from_addr, mails.data FROM mails WHERE mails.rcpt_addr = ? AND mails.id = ?")
if err != nil { if err != nil {

View File

@ -1,4 +1,4 @@
package main package web_server
templ styles() { templ styles() {
<style> <style>

View File

@ -3,12 +3,12 @@
pid=0 pid=0
get_ts() { get_ts() {
stat cmd/web_server pkg/** | grep Modify | awk '{$1=""; print $0}' | sed 's/^ //g' | sort -r | head -1 stat pkg/** | grep Modify | awk '{$1=""; print $0}' | sed 's/^ //g' | sort -r | head -1
} }
run_server() { run_server() {
make -B web make -B
./bin/web_server & ./bin/server &
pid=$! pid=$!
} }