refactor: fix init and use DI
* fix init misuse which makes running tests impossible since tests are run inside a temporary test directory which breaks env loading * use dependency injection pattern for server creation and global server context in route handlers
This commit is contained in:
parent
50244ee9ca
commit
c66e96bf3f
40
db/db.go
40
db/db.go
|
@ -2,44 +2,28 @@ package db
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"database/sql"
|
"database/sql"
|
||||||
"log"
|
|
||||||
|
|
||||||
"github.com/joho/godotenv"
|
|
||||||
_ "github.com/lib/pq"
|
_ "github.com/lib/pq"
|
||||||
"github.com/namsral/flag"
|
|
||||||
)
|
|
||||||
|
|
||||||
var (
|
|
||||||
db *DB
|
|
||||||
)
|
)
|
||||||
|
|
||||||
type DB struct {
|
type DB struct {
|
||||||
*sql.DB
|
*sql.DB
|
||||||
}
|
}
|
||||||
|
|
||||||
func init() {
|
func New(dbUrl string) (*DB, error) {
|
||||||
if err := godotenv.Load(); err != nil {
|
var (
|
||||||
log.Fatalf("error loading env vars: %s", err)
|
db_ *sql.DB
|
||||||
}
|
db *DB
|
||||||
var dbUrl string
|
err error
|
||||||
flag.StringVar(&dbUrl, "DATABASE_URL", "", "Database URL")
|
)
|
||||||
flag.Parse()
|
if db_, err = sql.Open("postgres", dbUrl); err != nil {
|
||||||
if dbUrl == "" {
|
return nil, err
|
||||||
log.Fatal("DATABASE_URL not set")
|
|
||||||
}
|
|
||||||
db = initDB(dbUrl)
|
|
||||||
}
|
|
||||||
|
|
||||||
func initDB(url string) *DB {
|
|
||||||
db, err := sql.Open("postgres", url)
|
|
||||||
if err != nil {
|
|
||||||
log.Fatal(err)
|
|
||||||
}
|
}
|
||||||
// test connection
|
// test connection
|
||||||
_, err = db.Exec("SELECT 1")
|
if _, err = db_.Exec("SELECT 1"); err != nil {
|
||||||
if err != nil {
|
return nil, err
|
||||||
log.Fatal(err)
|
|
||||||
}
|
}
|
||||||
// TODO: run migrations
|
// TODO: run migrations
|
||||||
return &DB{DB: db}
|
db = &DB{DB: db_}
|
||||||
|
return db, nil
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,7 +2,7 @@ package db
|
||||||
|
|
||||||
import "time"
|
import "time"
|
||||||
|
|
||||||
func CreateInvoice(invoice *Invoice) error {
|
func (db *DB) CreateInvoice(invoice *Invoice) error {
|
||||||
if err := db.QueryRow(""+
|
if err := db.QueryRow(""+
|
||||||
"INSERT INTO invoices(pubkey, msats, preimage, hash, bolt11, created_at, expires_at) "+
|
"INSERT INTO invoices(pubkey, msats, preimage, hash, bolt11, created_at, expires_at) "+
|
||||||
"VALUES($1, $2, $3, $4, $5, $6, $7) "+
|
"VALUES($1, $2, $3, $4, $5, $6, $7) "+
|
||||||
|
@ -18,7 +18,7 @@ type FetchInvoiceWhere struct {
|
||||||
Hash string
|
Hash string
|
||||||
}
|
}
|
||||||
|
|
||||||
func FetchInvoice(where *FetchInvoiceWhere, invoice *Invoice) error {
|
func (db *DB) FetchInvoice(where *FetchInvoiceWhere, invoice *Invoice) error {
|
||||||
var (
|
var (
|
||||||
query = "SELECT id, pubkey, msats, preimage, hash, bolt11, created_at, expires_at, confirmed_at, held_since FROM invoices "
|
query = "SELECT id, pubkey, msats, preimage, hash, bolt11, created_at, expires_at, confirmed_at, held_since FROM invoices "
|
||||||
args []any
|
args []any
|
||||||
|
@ -38,7 +38,7 @@ func FetchInvoice(where *FetchInvoiceWhere, invoice *Invoice) error {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func ConfirmInvoice(hash string, confirmedAt time.Time, msatsReceived int) error {
|
func (db *DB) ConfirmInvoice(hash string, confirmedAt time.Time, msatsReceived int) error {
|
||||||
if _, err := db.Exec("UPDATE invoices SET confirmed_at = $2, msats_received = $3 WHERE hash = $1", hash, confirmedAt, msatsReceived); err != nil {
|
if _, err := db.Exec("UPDATE invoices SET confirmed_at = $2, msats_received = $3 WHERE hash = $1", hash, confirmedAt, msatsReceived); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,18 +1,18 @@
|
||||||
package db
|
package db
|
||||||
|
|
||||||
func CreateLNAuth(lnAuth *LNAuth) error {
|
func (db *DB) CreateLNAuth(lnAuth *LNAuth) error {
|
||||||
err := db.QueryRow(
|
err := db.QueryRow(
|
||||||
"INSERT INTO lnauth(k1, lnurl) VALUES($1, $2) RETURNING session_id",
|
"INSERT INTO lnauth(k1, lnurl) VALUES($1, $2) RETURNING session_id",
|
||||||
lnAuth.K1, lnAuth.LNURL).Scan(&lnAuth.SessionId)
|
lnAuth.K1, lnAuth.LNURL).Scan(&lnAuth.SessionId)
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
func FetchSessionId(k1 string, sessionId *string) error {
|
func (db *DB) FetchSessionId(k1 string, sessionId *string) error {
|
||||||
err := db.QueryRow("SELECT session_id FROM lnauth WHERE k1 = $1", k1).Scan(sessionId)
|
err := db.QueryRow("SELECT session_id FROM lnauth WHERE k1 = $1", k1).Scan(sessionId)
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
func DeleteLNAuth(lnAuth *LNAuth) error {
|
func (db *DB) DeleteLNAuth(lnAuth *LNAuth) error {
|
||||||
_, err := db.Exec("DELETE FROM lnauth WHERE k1 = $1", lnAuth.K1)
|
_, err := db.Exec("DELETE FROM lnauth WHERE k1 = $1", lnAuth.K1)
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
22
db/market.go
22
db/market.go
|
@ -2,14 +2,20 @@ package db
|
||||||
|
|
||||||
import "database/sql"
|
import "database/sql"
|
||||||
|
|
||||||
func FetchMarket(marketId int, market *Market) error {
|
type FetchOrdersWhere struct {
|
||||||
|
MarketId int
|
||||||
|
Pubkey string
|
||||||
|
Confirmed bool
|
||||||
|
}
|
||||||
|
|
||||||
|
func (db *DB) FetchMarket(marketId int, market *Market) error {
|
||||||
if err := db.QueryRow("SELECT id, description FROM markets WHERE id = $1", marketId).Scan(&market.Id, &market.Description); err != nil {
|
if err := db.QueryRow("SELECT id, description FROM markets WHERE id = $1", marketId).Scan(&market.Id, &market.Description); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func FetchActiveMarkets(markets *[]Market) error {
|
func (db *DB) FetchActiveMarkets(markets *[]Market) error {
|
||||||
var (
|
var (
|
||||||
rows *sql.Rows
|
rows *sql.Rows
|
||||||
market Market
|
market Market
|
||||||
|
@ -26,7 +32,7 @@ func FetchActiveMarkets(markets *[]Market) error {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func FetchShares(marketId int, shares *[]Share) error {
|
func (db *DB) FetchShares(marketId int, shares *[]Share) error {
|
||||||
rows, err := db.Query("SELECT id, market_id, description FROM shares WHERE market_id = $1 ORDER BY description DESC", marketId)
|
rows, err := db.Query("SELECT id, market_id, description FROM shares WHERE market_id = $1 ORDER BY description DESC", marketId)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
|
@ -40,13 +46,7 @@ func FetchShares(marketId int, shares *[]Share) error {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
type FetchOrdersWhere struct {
|
func (db *DB) FetchOrders(where *FetchOrdersWhere, orders *[]Order) error {
|
||||||
MarketId int
|
|
||||||
Pubkey string
|
|
||||||
Confirmed bool
|
|
||||||
}
|
|
||||||
|
|
||||||
func FetchOrders(where *FetchOrdersWhere, orders *[]Order) error {
|
|
||||||
query := "" +
|
query := "" +
|
||||||
"SELECT o.id, share_id, o.pubkey, o.side, o.quantity, o.price, o.invoice_id, o.created_at, s.description, s.market_id, i.confirmed_at " +
|
"SELECT o.id, share_id, o.pubkey, o.side, o.quantity, o.price, o.invoice_id, o.created_at, s.description, s.market_id, i.confirmed_at " +
|
||||||
"FROM orders o " +
|
"FROM orders o " +
|
||||||
|
@ -79,7 +79,7 @@ func FetchOrders(where *FetchOrdersWhere, orders *[]Order) error {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func CreateOrder(order *Order) error {
|
func (db *DB) CreateOrder(order *Order) error {
|
||||||
if _, err := db.Exec(""+
|
if _, err := db.Exec(""+
|
||||||
"INSERT INTO orders(share_id, pubkey, side, quantity, price, invoice_id) "+
|
"INSERT INTO orders(share_id, pubkey, side, quantity, price, invoice_id) "+
|
||||||
"VALUES ($1, $2, $3, $4, $5, $6)",
|
"VALUES ($1, $2, $3, $4, $5, $6)",
|
||||||
|
|
|
@ -1,16 +1,16 @@
|
||||||
package db
|
package db
|
||||||
|
|
||||||
func CreateSession(s *Session) error {
|
func (db *DB) CreateSession(s *Session) error {
|
||||||
_, err := db.Exec("INSERT INTO sessions(pubkey, session_id) VALUES($1, $2)", s.Pubkey, s.SessionId)
|
_, err := db.Exec("INSERT INTO sessions(pubkey, session_id) VALUES($1, $2)", s.Pubkey, s.SessionId)
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
func FetchSession(s *Session) error {
|
func (db *DB) FetchSession(s *Session) error {
|
||||||
err := db.QueryRow("SELECT pubkey FROM sessions WHERE session_id = $1", s.SessionId).Scan(&s.Pubkey)
|
err := db.QueryRow("SELECT pubkey FROM sessions WHERE session_id = $1", s.SessionId).Scan(&s.Pubkey)
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
func DeleteSession(s *Session) error {
|
func (db *DB) DeleteSession(s *Session) error {
|
||||||
_, err := db.Exec("DELETE FROM sessions where session_id = $1", s.SessionId)
|
_, err := db.Exec("DELETE FROM sessions where session_id = $1", s.SessionId)
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
111
db/types.go
111
db/types.go
|
@ -6,61 +6,56 @@ import (
|
||||||
"gopkg.in/guregu/null.v4"
|
"gopkg.in/guregu/null.v4"
|
||||||
)
|
)
|
||||||
|
|
||||||
type Serial = int
|
type (
|
||||||
type UUID = string
|
Serial = int
|
||||||
|
UUID = string
|
||||||
type LNAuth struct {
|
LNAuth struct {
|
||||||
K1 string
|
K1 string
|
||||||
LNURL string
|
LNURL string
|
||||||
CreatdAt time.Time
|
CreatdAt time.Time
|
||||||
SessionId string
|
SessionId string
|
||||||
}
|
}
|
||||||
|
User struct {
|
||||||
type User struct {
|
Pubkey string
|
||||||
Pubkey string
|
LastSeen time.Time
|
||||||
LastSeen time.Time
|
}
|
||||||
}
|
Session struct {
|
||||||
|
Pubkey string
|
||||||
type Session struct {
|
SessionId string
|
||||||
Pubkey string
|
}
|
||||||
SessionId string
|
Market struct {
|
||||||
}
|
Id Serial
|
||||||
|
Description string
|
||||||
type Market struct {
|
Active bool
|
||||||
Id Serial
|
}
|
||||||
Description string
|
Share struct {
|
||||||
Active bool
|
Id UUID
|
||||||
}
|
MarketId int
|
||||||
|
Description string
|
||||||
type Share struct {
|
}
|
||||||
Id UUID
|
Invoice struct {
|
||||||
MarketId int
|
Id UUID
|
||||||
Description string
|
Pubkey string
|
||||||
}
|
Msats int64
|
||||||
|
MsatsReceived int64
|
||||||
type Invoice struct {
|
Preimage string
|
||||||
Id UUID
|
Hash string
|
||||||
Pubkey string
|
PaymentRequest string
|
||||||
Msats int64
|
CreatedAt time.Time
|
||||||
MsatsReceived int64
|
ExpiresAt time.Time
|
||||||
Preimage string
|
ConfirmedAt null.Time
|
||||||
Hash string
|
HeldSince null.Time
|
||||||
PaymentRequest string
|
}
|
||||||
CreatedAt time.Time
|
Order struct {
|
||||||
ExpiresAt time.Time
|
Id UUID
|
||||||
ConfirmedAt null.Time
|
CreatedAt time.Time
|
||||||
HeldSince null.Time
|
ShareId string `form:"share_id"`
|
||||||
}
|
Share
|
||||||
|
Pubkey string
|
||||||
type Order struct {
|
Side string `form:"side"`
|
||||||
Id UUID
|
Quantity int64 `form:"quantity"`
|
||||||
CreatedAt time.Time
|
Price int64 `form:"price"`
|
||||||
ShareId string `form:"share_id"`
|
InvoiceId UUID
|
||||||
Share
|
Invoice
|
||||||
Pubkey string
|
}
|
||||||
Side string `form:"side"`
|
)
|
||||||
Quantity int64 `form:"quantity"`
|
|
||||||
Price int64 `form:"price"`
|
|
||||||
InvoiceId UUID
|
|
||||||
Invoice
|
|
||||||
}
|
|
||||||
|
|
|
@ -1,13 +1,13 @@
|
||||||
package db
|
package db
|
||||||
|
|
||||||
func CreateUser(u *User) error {
|
func (db *DB) CreateUser(u *User) error {
|
||||||
_, err := db.Exec(
|
_, err := db.Exec(
|
||||||
"INSERT INTO users(pubkey) VALUES ($1) ON CONFLICT(pubkey) DO UPDATE SET last_seen = CURRENT_TIMESTAMP",
|
"INSERT INTO users(pubkey) VALUES ($1) ON CONFLICT(pubkey) DO UPDATE SET last_seen = CURRENT_TIMESTAMP",
|
||||||
u.Pubkey)
|
u.Pubkey)
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
func UpdateUser(u *User) error {
|
func (db *DB) UpdateUser(u *User) error {
|
||||||
_, err := db.Exec("UPDATE users SET last_seen = $1 WHERE pubkey = $2", u.LastSeen, u.Pubkey)
|
_, err := db.Exec("UPDATE users SET last_seen = $1 WHERE pubkey = $2", u.LastSeen, u.Pubkey)
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
|
@ -19,13 +19,17 @@ var (
|
||||||
Version string
|
Version string
|
||||||
)
|
)
|
||||||
|
|
||||||
func init() {
|
func Load(filenames ...string) error {
|
||||||
if err := godotenv.Load(); err != nil {
|
if err := godotenv.Load(); err != nil {
|
||||||
log.Fatalf("error loading env vars: %s", err)
|
return err
|
||||||
}
|
}
|
||||||
flag.StringVar(&PublicURL, "PUBLIC_URL", "delphi.market", "Public URL of website")
|
flag.StringVar(&PublicURL, "PUBLIC_URL", "delphi.market", "Public URL of website")
|
||||||
flag.IntVar(&Port, "PORT", 4321, "Server port")
|
flag.IntVar(&Port, "PORT", 4321, "Server port")
|
||||||
flag.StringVar(&Env, "ENV", "development", "Specify for which environment files should be built")
|
flag.StringVar(&Env, "ENV", "development", "Specify environment")
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func Parse() {
|
||||||
flag.Parse()
|
flag.Parse()
|
||||||
CommitLongSha = execCmd("git", "rev-parse", "HEAD")
|
CommitLongSha = execCmd("git", "rev-parse", "HEAD")
|
||||||
CommitShortSha = execCmd("git", "rev-parse", "--short", "HEAD")
|
CommitShortSha = execCmd("git", "rev-parse", "--short", "HEAD")
|
||||||
|
|
|
@ -12,7 +12,7 @@ import (
|
||||||
"github.com/lightningnetwork/lnd/lnwire"
|
"github.com/lightningnetwork/lnd/lnwire"
|
||||||
)
|
)
|
||||||
|
|
||||||
func CreateInvoice(pubkey string, msats int64) (*db.Invoice, error) {
|
func (lnd *LNDClient) CreateInvoice(d *db.DB, pubkey string, msats int64) (*db.Invoice, error) {
|
||||||
var (
|
var (
|
||||||
expiry time.Duration = time.Hour
|
expiry time.Duration = time.Hour
|
||||||
preimage lntypes.Preimage
|
preimage lntypes.Preimage
|
||||||
|
@ -45,13 +45,13 @@ func CreateInvoice(pubkey string, msats int64) (*db.Invoice, error) {
|
||||||
CreatedAt: lnInvoice.CreationDate,
|
CreatedAt: lnInvoice.CreationDate,
|
||||||
ExpiresAt: lnInvoice.CreationDate.Add(expiry),
|
ExpiresAt: lnInvoice.CreationDate.Add(expiry),
|
||||||
}
|
}
|
||||||
if err := db.CreateInvoice(dbInvoice); err != nil {
|
if err := d.CreateInvoice(dbInvoice); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
return dbInvoice, nil
|
return dbInvoice, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func CheckInvoice(hash lntypes.Hash) {
|
func (lnd *LNDClient) CheckInvoice(d *db.DB, hash lntypes.Hash) {
|
||||||
var (
|
var (
|
||||||
pollInterval = 5 * time.Second
|
pollInterval = 5 * time.Second
|
||||||
invoice db.Invoice
|
invoice db.Invoice
|
||||||
|
@ -60,12 +60,7 @@ func CheckInvoice(hash lntypes.Hash) {
|
||||||
err error
|
err error
|
||||||
)
|
)
|
||||||
|
|
||||||
if !Enabled {
|
if err = d.FetchInvoice(&db.FetchInvoiceWhere{Hash: hash.String()}, &invoice); err != nil {
|
||||||
log.Printf("LND disabled, skipping checking invoice: hash=%s", hash)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
if err = db.FetchInvoice(&db.FetchInvoiceWhere{Hash: hash.String()}, &invoice); err != nil {
|
|
||||||
log.Println(err)
|
log.Println(err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
@ -100,7 +95,7 @@ func CheckInvoice(hash lntypes.Hash) {
|
||||||
handleLoopError(err)
|
handleLoopError(err)
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
if err = db.ConfirmInvoice(hash.String(), time.Now(), int(lnInvoice.AmountPaid)); err != nil {
|
if err = d.ConfirmInvoice(hash.String(), time.Now(), int(lnInvoice.AmountPaid)); err != nil {
|
||||||
handleLoopError(err)
|
handleLoopError(err)
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
44
lnd/lnd.go
44
lnd/lnd.go
|
@ -3,47 +3,25 @@ package lnd
|
||||||
import (
|
import (
|
||||||
"log"
|
"log"
|
||||||
|
|
||||||
"github.com/joho/godotenv"
|
|
||||||
"github.com/lightninglabs/lndclient"
|
"github.com/lightninglabs/lndclient"
|
||||||
"github.com/namsral/flag"
|
|
||||||
)
|
|
||||||
|
|
||||||
var (
|
|
||||||
lnd *LNDClient
|
|
||||||
Enabled bool
|
|
||||||
)
|
)
|
||||||
|
|
||||||
type LNDClient struct {
|
type LNDClient struct {
|
||||||
lndclient.GrpcLndServices
|
*lndclient.GrpcLndServices
|
||||||
}
|
}
|
||||||
|
|
||||||
func init() {
|
type LNDConfig = lndclient.LndServicesConfig
|
||||||
|
|
||||||
|
func New(config *LNDConfig) (*LNDClient, error) {
|
||||||
var (
|
var (
|
||||||
lndCert string
|
rcpLndServices *lndclient.GrpcLndServices
|
||||||
lndMacaroonDir string
|
lnd *LNDClient
|
||||||
lndHost string
|
|
||||||
rpcLndServices *lndclient.GrpcLndServices
|
|
||||||
err error
|
err error
|
||||||
)
|
)
|
||||||
if err = godotenv.Load(); err != nil {
|
if rcpLndServices, err = lndclient.NewLndServices(config); err != nil {
|
||||||
log.Fatalf("error loading env vars: %s", err)
|
return nil, err
|
||||||
}
|
}
|
||||||
flag.StringVar(&lndCert, "LND_CERT", "", "Path to LND TLS certificate")
|
lnd = &LNDClient{GrpcLndServices: rcpLndServices}
|
||||||
flag.StringVar(&lndMacaroonDir, "LND_MACAROON_DIR", "", "LND macaroon directory")
|
log.Printf("Connected to %s running LND v%s", config.LndAddress, lnd.Version.Version)
|
||||||
flag.StringVar(&lndHost, "LND_HOST", "localhost:10001", "LND gRPC server address")
|
return lnd, nil
|
||||||
flag.Parse()
|
|
||||||
if rpcLndServices, err = lndclient.NewLndServices(&lndclient.LndServicesConfig{
|
|
||||||
LndAddress: lndHost,
|
|
||||||
MacaroonDir: lndMacaroonDir,
|
|
||||||
TLSPath: lndCert,
|
|
||||||
// TODO: make network configurable
|
|
||||||
Network: lndclient.NetworkRegtest,
|
|
||||||
}); err != nil {
|
|
||||||
log.Println(err)
|
|
||||||
Enabled = false
|
|
||||||
return
|
|
||||||
}
|
|
||||||
lnd = &LNDClient{GrpcLndServices: *rpcLndServices}
|
|
||||||
log.Printf("Connected to %s running LND v%s", lndHost, lnd.Version.Version)
|
|
||||||
Enabled = true
|
|
||||||
}
|
}
|
||||||
|
|
61
main.go
61
main.go
|
@ -5,8 +5,13 @@ import (
|
||||||
"log"
|
"log"
|
||||||
"net/http"
|
"net/http"
|
||||||
|
|
||||||
|
"git.ekzyis.com/ekzyis/delphi.market/db"
|
||||||
"git.ekzyis.com/ekzyis/delphi.market/env"
|
"git.ekzyis.com/ekzyis/delphi.market/env"
|
||||||
|
"git.ekzyis.com/ekzyis/delphi.market/lnd"
|
||||||
"git.ekzyis.com/ekzyis/delphi.market/server"
|
"git.ekzyis.com/ekzyis/delphi.market/server"
|
||||||
|
"git.ekzyis.com/ekzyis/delphi.market/server/router"
|
||||||
|
"github.com/lightninglabs/lndclient"
|
||||||
|
"github.com/namsral/flag"
|
||||||
)
|
)
|
||||||
|
|
||||||
var (
|
var (
|
||||||
|
@ -14,11 +19,65 @@ var (
|
||||||
)
|
)
|
||||||
|
|
||||||
func init() {
|
func init() {
|
||||||
|
var (
|
||||||
|
dbUrl string
|
||||||
|
lndAddress string
|
||||||
|
lndCert string
|
||||||
|
lndMacaroonDir string
|
||||||
|
db_ *db.DB
|
||||||
|
lnd_ *lnd.LNDClient
|
||||||
|
ctx router.ServerContext
|
||||||
|
err error
|
||||||
|
)
|
||||||
|
if err = env.Load(); err != nil {
|
||||||
|
log.Fatalf("error loading env vars: %v", err)
|
||||||
|
}
|
||||||
|
flag.StringVar(&dbUrl, "DATABASE_URL", "delphi.market", "Public URL of website")
|
||||||
|
flag.StringVar(&lndAddress, "LND_ADDRESS", "localhost:10001", "LND gRPC server address")
|
||||||
|
flag.StringVar(&lndCert, "LND_CERT", "", "Path to LND TLS certificate")
|
||||||
|
flag.StringVar(&lndMacaroonDir, "LND_MACAROON_DIR", "", "LND macaroon directory")
|
||||||
|
env.Parse()
|
||||||
|
figlet()
|
||||||
log.Printf("Commit: %s", env.CommitShortSha)
|
log.Printf("Commit: %s", env.CommitShortSha)
|
||||||
log.Printf("Public URL: %s", env.PublicURL)
|
log.Printf("Public URL: %s", env.PublicURL)
|
||||||
log.Printf("Environment: %s", env.Env)
|
log.Printf("Environment: %s", env.Env)
|
||||||
|
|
||||||
s = server.NewServer()
|
if db_, err = db.New(dbUrl); err != nil {
|
||||||
|
log.Fatalf("error connecting to database: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if lnd_, err = lnd.New(&lnd.LNDConfig{
|
||||||
|
LndAddress: lndAddress,
|
||||||
|
TLSPath: lndCert,
|
||||||
|
MacaroonDir: lndMacaroonDir,
|
||||||
|
Network: lndclient.NetworkRegtest,
|
||||||
|
}); err != nil {
|
||||||
|
log.Printf("[warn] error connecting to LND: %v\n", err)
|
||||||
|
lnd_ = nil
|
||||||
|
}
|
||||||
|
|
||||||
|
ctx = server.ServerContext{
|
||||||
|
PublicURL: env.PublicURL,
|
||||||
|
CommitShortSha: env.CommitShortSha,
|
||||||
|
CommitLongSha: env.CommitLongSha,
|
||||||
|
Version: env.Version,
|
||||||
|
Db: db_,
|
||||||
|
Lnd: lnd_,
|
||||||
|
}
|
||||||
|
s = server.New(ctx)
|
||||||
|
}
|
||||||
|
|
||||||
|
func figlet() {
|
||||||
|
log.Println(
|
||||||
|
"\n" +
|
||||||
|
" _ _ _ _ \n" +
|
||||||
|
" __| | ___| |_ __ | |__ (_)\n" +
|
||||||
|
" / _` |/ _ \\ | '_ \\| '_ \\| |\n" +
|
||||||
|
"| (_| | __/ | |_) | | | | |\n" +
|
||||||
|
" \\__,_|\\___|_| .__/|_| |_|_|\n" +
|
||||||
|
" |_| .market \n" +
|
||||||
|
"----------------------------",
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
|
|
|
@ -0,0 +1,34 @@
|
||||||
|
package context
|
||||||
|
|
||||||
|
import (
|
||||||
|
"git.ekzyis.com/ekzyis/delphi.market/db"
|
||||||
|
"git.ekzyis.com/ekzyis/delphi.market/lnd"
|
||||||
|
"github.com/labstack/echo/v4"
|
||||||
|
)
|
||||||
|
|
||||||
|
type ServerContext struct {
|
||||||
|
Environment string
|
||||||
|
PublicURL string
|
||||||
|
CommitShortSha string
|
||||||
|
CommitLongSha string
|
||||||
|
Version string
|
||||||
|
Db *db.DB
|
||||||
|
Lnd *lnd.LNDClient
|
||||||
|
}
|
||||||
|
|
||||||
|
func (sc *ServerContext) Render(c echo.Context, code int, name string, data map[string]any) error {
|
||||||
|
envVars := map[string]any{
|
||||||
|
"PUBLIC_URL": sc.PublicURL,
|
||||||
|
"COMMIT_SHORT_SHA": sc.CommitShortSha,
|
||||||
|
"COMMIT_LONG_SHA": sc.CommitLongSha,
|
||||||
|
"VERSION": sc.Version,
|
||||||
|
}
|
||||||
|
merge(&data, &envVars)
|
||||||
|
return c.Render(code, name, data)
|
||||||
|
}
|
||||||
|
|
||||||
|
func merge[T comparable](target *map[T]any, src *map[T]any) {
|
||||||
|
for k, v := range *src {
|
||||||
|
(*target)[k] = v
|
||||||
|
}
|
||||||
|
}
|
|
@ -4,25 +4,25 @@ import (
|
||||||
"net/http"
|
"net/http"
|
||||||
|
|
||||||
"git.ekzyis.com/ekzyis/delphi.market/db"
|
"git.ekzyis.com/ekzyis/delphi.market/db"
|
||||||
"git.ekzyis.com/ekzyis/delphi.market/lib"
|
"git.ekzyis.com/ekzyis/delphi.market/server/router/context"
|
||||||
"github.com/labstack/echo/v4"
|
"github.com/labstack/echo/v4"
|
||||||
)
|
)
|
||||||
|
|
||||||
func HandleIndex(envVars map[string]any) echo.HandlerFunc {
|
func HandleIndex(sc context.ServerContext) echo.HandlerFunc {
|
||||||
return func(c echo.Context) error {
|
return func(c echo.Context) error {
|
||||||
var (
|
var (
|
||||||
markets []db.Market
|
markets []db.Market
|
||||||
err error
|
err error
|
||||||
data map[string]any
|
data map[string]any
|
||||||
)
|
)
|
||||||
if err = db.FetchActiveMarkets(&markets); err != nil {
|
if err = sc.Db.FetchActiveMarkets(&markets); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
data = map[string]any{
|
data = map[string]any{
|
||||||
"session": c.Get("session"),
|
"session": c.Get("session"),
|
||||||
"markets": markets,
|
"markets": markets,
|
||||||
}
|
}
|
||||||
lib.Merge(&data, &envVars)
|
|
||||||
return c.Render(http.StatusOK, "index.html", data)
|
return sc.Render(c, http.StatusOK, "index.html", data)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -7,12 +7,12 @@ import (
|
||||||
|
|
||||||
"git.ekzyis.com/ekzyis/delphi.market/db"
|
"git.ekzyis.com/ekzyis/delphi.market/db"
|
||||||
"git.ekzyis.com/ekzyis/delphi.market/lib"
|
"git.ekzyis.com/ekzyis/delphi.market/lib"
|
||||||
"git.ekzyis.com/ekzyis/delphi.market/lnd"
|
"git.ekzyis.com/ekzyis/delphi.market/server/router/context"
|
||||||
"github.com/labstack/echo/v4"
|
"github.com/labstack/echo/v4"
|
||||||
"github.com/lightningnetwork/lnd/lntypes"
|
"github.com/lightningnetwork/lnd/lntypes"
|
||||||
)
|
)
|
||||||
|
|
||||||
func HandleInvoiceAPI(envVars map[string]any) echo.HandlerFunc {
|
func HandleInvoiceAPI(sc context.ServerContext) echo.HandlerFunc {
|
||||||
return func(c echo.Context) error {
|
return func(c echo.Context) error {
|
||||||
var (
|
var (
|
||||||
invoiceId string
|
invoiceId string
|
||||||
|
@ -21,7 +21,7 @@ func HandleInvoiceAPI(envVars map[string]any) echo.HandlerFunc {
|
||||||
err error
|
err error
|
||||||
)
|
)
|
||||||
invoiceId = c.Param("id")
|
invoiceId = c.Param("id")
|
||||||
if err = db.FetchInvoice(&db.FetchInvoiceWhere{Id: invoiceId}, &invoice); err == sql.ErrNoRows {
|
if err = sc.Db.FetchInvoice(&db.FetchInvoiceWhere{Id: invoiceId}, &invoice); err == sql.ErrNoRows {
|
||||||
return echo.NewHTTPError(http.StatusNotFound)
|
return echo.NewHTTPError(http.StatusNotFound)
|
||||||
} else if err != nil {
|
} else if err != nil {
|
||||||
return err
|
return err
|
||||||
|
@ -34,7 +34,7 @@ func HandleInvoiceAPI(envVars map[string]any) echo.HandlerFunc {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func HandleInvoice(envVars map[string]any) echo.HandlerFunc {
|
func HandleInvoice(sc context.ServerContext) echo.HandlerFunc {
|
||||||
return func(c echo.Context) error {
|
return func(c echo.Context) error {
|
||||||
var (
|
var (
|
||||||
invoiceId string
|
invoiceId string
|
||||||
|
@ -46,7 +46,7 @@ func HandleInvoice(envVars map[string]any) echo.HandlerFunc {
|
||||||
err error
|
err error
|
||||||
)
|
)
|
||||||
invoiceId = c.Param("id")
|
invoiceId = c.Param("id")
|
||||||
if err = db.FetchInvoice(&db.FetchInvoiceWhere{Id: invoiceId}, &invoice); err == sql.ErrNoRows {
|
if err = sc.Db.FetchInvoice(&db.FetchInvoiceWhere{Id: invoiceId}, &invoice); err == sql.ErrNoRows {
|
||||||
return echo.NewHTTPError(http.StatusNotFound)
|
return echo.NewHTTPError(http.StatusNotFound)
|
||||||
} else if err != nil {
|
} else if err != nil {
|
||||||
return err
|
return err
|
||||||
|
@ -57,7 +57,7 @@ func HandleInvoice(envVars map[string]any) echo.HandlerFunc {
|
||||||
if hash, err = lntypes.MakeHashFromStr(invoice.Hash); err != nil {
|
if hash, err = lntypes.MakeHashFromStr(invoice.Hash); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
go lnd.CheckInvoice(hash)
|
go sc.Lnd.CheckInvoice(sc.Db, hash)
|
||||||
if qr, err = lib.ToQR(invoice.PaymentRequest); err != nil {
|
if qr, err = lib.ToQR(invoice.PaymentRequest); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
@ -73,6 +73,6 @@ func HandleInvoice(envVars map[string]any) echo.HandlerFunc {
|
||||||
"lnurl": invoice.PaymentRequest,
|
"lnurl": invoice.PaymentRequest,
|
||||||
"qr": qr,
|
"qr": qr,
|
||||||
}
|
}
|
||||||
return c.Render(http.StatusOK, "invoice.html", data)
|
return sc.Render(c, http.StatusOK, "invoice.html", data)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -8,10 +8,11 @@ import (
|
||||||
"git.ekzyis.com/ekzyis/delphi.market/db"
|
"git.ekzyis.com/ekzyis/delphi.market/db"
|
||||||
"git.ekzyis.com/ekzyis/delphi.market/lib"
|
"git.ekzyis.com/ekzyis/delphi.market/lib"
|
||||||
"git.ekzyis.com/ekzyis/delphi.market/server/auth"
|
"git.ekzyis.com/ekzyis/delphi.market/server/auth"
|
||||||
|
"git.ekzyis.com/ekzyis/delphi.market/server/router/context"
|
||||||
"github.com/labstack/echo/v4"
|
"github.com/labstack/echo/v4"
|
||||||
)
|
)
|
||||||
|
|
||||||
func HandleLogin(envVars map[string]any) echo.HandlerFunc {
|
func HandleLogin(sc context.ServerContext) echo.HandlerFunc {
|
||||||
return func(c echo.Context) error {
|
return func(c echo.Context) error {
|
||||||
var (
|
var (
|
||||||
lnAuth *auth.LNAuth
|
lnAuth *auth.LNAuth
|
||||||
|
@ -25,7 +26,7 @@ func HandleLogin(envVars map[string]any) echo.HandlerFunc {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
dbLnAuth = db.LNAuth{K1: lnAuth.K1, LNURL: lnAuth.LNURL}
|
dbLnAuth = db.LNAuth{K1: lnAuth.K1, LNURL: lnAuth.LNURL}
|
||||||
if err = db.CreateLNAuth(&dbLnAuth); err != nil {
|
if err = sc.Db.CreateLNAuth(&dbLnAuth); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
c.SetCookie(&http.Cookie{Name: "session", HttpOnly: true, Path: "/", Value: dbLnAuth.SessionId, Secure: true, Expires: expires})
|
c.SetCookie(&http.Cookie{Name: "session", HttpOnly: true, Path: "/", Value: dbLnAuth.SessionId, Secure: true, Expires: expires})
|
||||||
|
@ -37,12 +38,11 @@ func HandleLogin(envVars map[string]any) echo.HandlerFunc {
|
||||||
"lnurl": lnAuth.LNURL,
|
"lnurl": lnAuth.LNURL,
|
||||||
"qr": qr,
|
"qr": qr,
|
||||||
}
|
}
|
||||||
lib.Merge(&data, &envVars)
|
return sc.Render(c, http.StatusOK, "login.html", data)
|
||||||
return c.Render(http.StatusOK, "login.html", data)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func HandleLoginCallback(envVars map[string]any) echo.HandlerFunc {
|
func HandleLoginCallback(sc context.ServerContext) echo.HandlerFunc {
|
||||||
return func(c echo.Context) error {
|
return func(c echo.Context) error {
|
||||||
var (
|
var (
|
||||||
query auth.LNAuthResponse
|
query auth.LNAuthResponse
|
||||||
|
@ -52,7 +52,7 @@ func HandleLoginCallback(envVars map[string]any) echo.HandlerFunc {
|
||||||
if err := c.Bind(&query); err != nil {
|
if err := c.Bind(&query); err != nil {
|
||||||
return echo.NewHTTPError(http.StatusBadRequest)
|
return echo.NewHTTPError(http.StatusBadRequest)
|
||||||
}
|
}
|
||||||
if err = db.FetchSessionId(query.K1, &sessionId); err == sql.ErrNoRows {
|
if err = sc.Db.FetchSessionId(query.K1, &sessionId); err == sql.ErrNoRows {
|
||||||
return echo.NewHTTPError(http.StatusNotFound, map[string]string{"reason": "session not found"})
|
return echo.NewHTTPError(http.StatusNotFound, map[string]string{"reason": "session not found"})
|
||||||
} else if err != nil {
|
} else if err != nil {
|
||||||
return err
|
return err
|
||||||
|
@ -62,13 +62,13 @@ func HandleLoginCallback(envVars map[string]any) echo.HandlerFunc {
|
||||||
} else if !ok {
|
} else if !ok {
|
||||||
return echo.NewHTTPError(http.StatusBadRequest, map[string]string{"reason": "bad signature"})
|
return echo.NewHTTPError(http.StatusBadRequest, map[string]string{"reason": "bad signature"})
|
||||||
}
|
}
|
||||||
if err = db.CreateUser(&db.User{Pubkey: query.Key}); err != nil {
|
if err = sc.Db.CreateUser(&db.User{Pubkey: query.Key}); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
if err = db.CreateSession(&db.Session{Pubkey: query.Key, SessionId: sessionId}); err != nil {
|
if err = sc.Db.CreateSession(&db.Session{Pubkey: query.Key, SessionId: sessionId}); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
if err = db.DeleteLNAuth(&db.LNAuth{K1: query.K1}); err != nil {
|
if err = sc.Db.DeleteLNAuth(&db.LNAuth{K1: query.K1}); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
return c.JSON(http.StatusOK, map[string]string{"status": "OK"})
|
return c.JSON(http.StatusOK, map[string]string{"status": "OK"})
|
||||||
|
|
|
@ -5,10 +5,11 @@ import (
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"git.ekzyis.com/ekzyis/delphi.market/db"
|
"git.ekzyis.com/ekzyis/delphi.market/db"
|
||||||
|
"git.ekzyis.com/ekzyis/delphi.market/server/router/context"
|
||||||
"github.com/labstack/echo/v4"
|
"github.com/labstack/echo/v4"
|
||||||
)
|
)
|
||||||
|
|
||||||
func HandleLogout(envVars map[string]any) echo.HandlerFunc {
|
func HandleLogout(sc context.ServerContext) echo.HandlerFunc {
|
||||||
return func(c echo.Context) error {
|
return func(c echo.Context) error {
|
||||||
var (
|
var (
|
||||||
cookie *http.Cookie
|
cookie *http.Cookie
|
||||||
|
@ -20,7 +21,7 @@ func HandleLogout(envVars map[string]any) echo.HandlerFunc {
|
||||||
return c.Redirect(http.StatusSeeOther, "/")
|
return c.Redirect(http.StatusSeeOther, "/")
|
||||||
}
|
}
|
||||||
sessionId = cookie.Value
|
sessionId = cookie.Value
|
||||||
if err = db.DeleteSession(&db.Session{SessionId: sessionId}); err != nil {
|
if err = sc.Db.DeleteSession(&db.Session{SessionId: sessionId}); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
// tell browser that cookie is expired and thus can be deleted
|
// tell browser that cookie is expired and thus can be deleted
|
||||||
|
|
|
@ -9,12 +9,12 @@ import (
|
||||||
"git.ekzyis.com/ekzyis/delphi.market/db"
|
"git.ekzyis.com/ekzyis/delphi.market/db"
|
||||||
"git.ekzyis.com/ekzyis/delphi.market/env"
|
"git.ekzyis.com/ekzyis/delphi.market/env"
|
||||||
"git.ekzyis.com/ekzyis/delphi.market/lib"
|
"git.ekzyis.com/ekzyis/delphi.market/lib"
|
||||||
"git.ekzyis.com/ekzyis/delphi.market/lnd"
|
"git.ekzyis.com/ekzyis/delphi.market/server/router/context"
|
||||||
"github.com/labstack/echo/v4"
|
"github.com/labstack/echo/v4"
|
||||||
"github.com/lightningnetwork/lnd/lntypes"
|
"github.com/lightningnetwork/lnd/lntypes"
|
||||||
)
|
)
|
||||||
|
|
||||||
func HandleMarket(envVars map[string]any) echo.HandlerFunc {
|
func HandleMarket(sc context.ServerContext) echo.HandlerFunc {
|
||||||
return func(c echo.Context) error {
|
return func(c echo.Context) error {
|
||||||
var (
|
var (
|
||||||
marketId int64
|
marketId int64
|
||||||
|
@ -27,15 +27,15 @@ func HandleMarket(envVars map[string]any) echo.HandlerFunc {
|
||||||
if marketId, err = strconv.ParseInt(c.Param("id"), 10, 64); err != nil {
|
if marketId, err = strconv.ParseInt(c.Param("id"), 10, 64); err != nil {
|
||||||
return echo.NewHTTPError(http.StatusBadRequest, "Bad Request")
|
return echo.NewHTTPError(http.StatusBadRequest, "Bad Request")
|
||||||
}
|
}
|
||||||
if err = db.FetchMarket(int(marketId), &market); err == sql.ErrNoRows {
|
if err = sc.Db.FetchMarket(int(marketId), &market); err == sql.ErrNoRows {
|
||||||
return echo.NewHTTPError(http.StatusNotFound, "Not Found")
|
return echo.NewHTTPError(http.StatusNotFound, "Not Found")
|
||||||
} else if err != nil {
|
} else if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
if err = db.FetchShares(market.Id, &shares); err != nil {
|
if err = sc.Db.FetchShares(market.Id, &shares); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
if err = db.FetchOrders(&db.FetchOrdersWhere{MarketId: market.Id, Confirmed: true}, &orders); err != nil {
|
if err = sc.Db.FetchOrders(&db.FetchOrdersWhere{MarketId: market.Id, Confirmed: true}, &orders); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
data = map[string]any{
|
data = map[string]any{
|
||||||
|
@ -48,12 +48,11 @@ func HandleMarket(envVars map[string]any) echo.HandlerFunc {
|
||||||
"NoShare": shares[1],
|
"NoShare": shares[1],
|
||||||
"Orders": orders,
|
"Orders": orders,
|
||||||
}
|
}
|
||||||
lib.Merge(&data, &envVars)
|
return sc.Render(c, http.StatusOK, "market.html", data)
|
||||||
return c.Render(http.StatusOK, "market.html", data)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func HandlePostOrder(envVars map[string]any) echo.HandlerFunc {
|
func HandlePostOrder(sc context.ServerContext) echo.HandlerFunc {
|
||||||
return func(c echo.Context) error {
|
return func(c echo.Context) error {
|
||||||
var (
|
var (
|
||||||
marketId string
|
marketId string
|
||||||
|
@ -86,7 +85,7 @@ func HandlePostOrder(envVars map[string]any) echo.HandlerFunc {
|
||||||
// TODO: if SELL order, check share balance of user
|
// TODO: if SELL order, check share balance of user
|
||||||
|
|
||||||
// Create HODL invoice
|
// Create HODL invoice
|
||||||
if invoice, err = lnd.CreateInvoice(o.Pubkey, msats); err != nil {
|
if invoice, err = sc.Lnd.CreateInvoice(sc.Db, o.Pubkey, msats); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
// Create QR code to pay HODL invoice
|
// Create QR code to pay HODL invoice
|
||||||
|
@ -98,11 +97,11 @@ func HandlePostOrder(envVars map[string]any) echo.HandlerFunc {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Start goroutine to poll status and update invoice in background
|
// Start goroutine to poll status and update invoice in background
|
||||||
go lnd.CheckInvoice(hash)
|
go sc.Lnd.CheckInvoice(sc.Db, hash)
|
||||||
|
|
||||||
// Create (unconfirmed) order
|
// Create (unconfirmed) order
|
||||||
o.InvoiceId = invoice.Id
|
o.InvoiceId = invoice.Id
|
||||||
if err := db.CreateOrder(&o); err != nil {
|
if err := sc.Db.CreateOrder(&o); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -115,7 +114,6 @@ func HandlePostOrder(envVars map[string]any) echo.HandlerFunc {
|
||||||
"invoice": *invoice,
|
"invoice": *invoice,
|
||||||
"redirectURL": fmt.Sprintf("https://%s/market/%s", env.PublicURL, marketId),
|
"redirectURL": fmt.Sprintf("https://%s/market/%s", env.PublicURL, marketId),
|
||||||
}
|
}
|
||||||
lib.Merge(&data, &envVars)
|
return sc.Render(c, http.StatusPaymentRequired, "invoice.html", data)
|
||||||
return c.Render(http.StatusPaymentRequired, "invoice.html", data)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -5,10 +5,11 @@ import (
|
||||||
"net/http"
|
"net/http"
|
||||||
|
|
||||||
"git.ekzyis.com/ekzyis/delphi.market/db"
|
"git.ekzyis.com/ekzyis/delphi.market/db"
|
||||||
|
"git.ekzyis.com/ekzyis/delphi.market/server/router/context"
|
||||||
"github.com/labstack/echo/v4"
|
"github.com/labstack/echo/v4"
|
||||||
)
|
)
|
||||||
|
|
||||||
func HandleCheckSession(envVars map[string]any) echo.HandlerFunc {
|
func HandleCheckSession(sc context.ServerContext) echo.HandlerFunc {
|
||||||
return func(c echo.Context) error {
|
return func(c echo.Context) error {
|
||||||
var (
|
var (
|
||||||
cookie *http.Cookie
|
cookie *http.Cookie
|
||||||
|
@ -19,7 +20,7 @@ func HandleCheckSession(envVars map[string]any) echo.HandlerFunc {
|
||||||
return echo.NewHTTPError(http.StatusBadRequest, map[string]string{"reason": "cookie required"})
|
return echo.NewHTTPError(http.StatusBadRequest, map[string]string{"reason": "cookie required"})
|
||||||
}
|
}
|
||||||
s = db.Session{SessionId: cookie.Value}
|
s = db.Session{SessionId: cookie.Value}
|
||||||
if err = db.FetchSession(&s); err == sql.ErrNoRows {
|
if err = sc.Db.FetchSession(&s); err == sql.ErrNoRows {
|
||||||
return echo.NewHTTPError(http.StatusNotFound, map[string]string{"reason": "session not found"})
|
return echo.NewHTTPError(http.StatusNotFound, map[string]string{"reason": "session not found"})
|
||||||
} else if err != nil {
|
} else if err != nil {
|
||||||
return echo.NewHTTPError(http.StatusInternalServerError)
|
return echo.NewHTTPError(http.StatusInternalServerError)
|
||||||
|
|
|
@ -4,11 +4,11 @@ import (
|
||||||
"net/http"
|
"net/http"
|
||||||
|
|
||||||
"git.ekzyis.com/ekzyis/delphi.market/db"
|
"git.ekzyis.com/ekzyis/delphi.market/db"
|
||||||
"git.ekzyis.com/ekzyis/delphi.market/lib"
|
"git.ekzyis.com/ekzyis/delphi.market/server/router/context"
|
||||||
"github.com/labstack/echo/v4"
|
"github.com/labstack/echo/v4"
|
||||||
)
|
)
|
||||||
|
|
||||||
func HandleUser(envVars map[string]any) echo.HandlerFunc {
|
func HandleUser(sc context.ServerContext) echo.HandlerFunc {
|
||||||
return func(c echo.Context) error {
|
return func(c echo.Context) error {
|
||||||
var (
|
var (
|
||||||
u db.User
|
u db.User
|
||||||
|
@ -17,7 +17,7 @@ func HandleUser(envVars map[string]any) echo.HandlerFunc {
|
||||||
data map[string]any
|
data map[string]any
|
||||||
)
|
)
|
||||||
u = c.Get("session").(db.User)
|
u = c.Get("session").(db.User)
|
||||||
if err = db.FetchOrders(&db.FetchOrdersWhere{Pubkey: u.Pubkey}, &orders); err != nil {
|
if err = sc.Db.FetchOrders(&db.FetchOrdersWhere{Pubkey: u.Pubkey}, &orders); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
data = map[string]any{
|
data = map[string]any{
|
||||||
|
@ -25,7 +25,6 @@ func HandleUser(envVars map[string]any) echo.HandlerFunc {
|
||||||
"user": u,
|
"user": u,
|
||||||
"Orders": orders,
|
"Orders": orders,
|
||||||
}
|
}
|
||||||
lib.Merge(&data, &envVars)
|
return sc.Render(c, http.StatusOK, "user.html", data)
|
||||||
return c.Render(http.StatusOK, "user.html", data)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -3,14 +3,14 @@ package middleware
|
||||||
import (
|
import (
|
||||||
"net/http"
|
"net/http"
|
||||||
|
|
||||||
"git.ekzyis.com/ekzyis/delphi.market/lnd"
|
"git.ekzyis.com/ekzyis/delphi.market/server/router/context"
|
||||||
"github.com/labstack/echo/v4"
|
"github.com/labstack/echo/v4"
|
||||||
)
|
)
|
||||||
|
|
||||||
func LNDGuard(envVars map[string]any) echo.MiddlewareFunc {
|
func LNDGuard(sc context.ServerContext) echo.MiddlewareFunc {
|
||||||
return func(next echo.HandlerFunc) echo.HandlerFunc {
|
return func(next echo.HandlerFunc) echo.HandlerFunc {
|
||||||
return func(c echo.Context) error {
|
return func(c echo.Context) error {
|
||||||
if lnd.Enabled {
|
if sc.Lnd != nil {
|
||||||
return next(c)
|
return next(c)
|
||||||
}
|
}
|
||||||
return echo.NewHTTPError(http.StatusMethodNotAllowed)
|
return echo.NewHTTPError(http.StatusMethodNotAllowed)
|
||||||
|
|
|
@ -6,10 +6,11 @@ import (
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"git.ekzyis.com/ekzyis/delphi.market/db"
|
"git.ekzyis.com/ekzyis/delphi.market/db"
|
||||||
|
"git.ekzyis.com/ekzyis/delphi.market/server/router/context"
|
||||||
"github.com/labstack/echo/v4"
|
"github.com/labstack/echo/v4"
|
||||||
)
|
)
|
||||||
|
|
||||||
func Session(envVars map[string]any) echo.MiddlewareFunc {
|
func Session(sc context.ServerContext) echo.MiddlewareFunc {
|
||||||
return func(next echo.HandlerFunc) echo.HandlerFunc {
|
return func(next echo.HandlerFunc) echo.HandlerFunc {
|
||||||
return func(c echo.Context) error {
|
return func(c echo.Context) error {
|
||||||
var (
|
var (
|
||||||
|
@ -23,10 +24,10 @@ func Session(envVars map[string]any) echo.MiddlewareFunc {
|
||||||
return next(c)
|
return next(c)
|
||||||
}
|
}
|
||||||
s = &db.Session{SessionId: cookie.Value}
|
s = &db.Session{SessionId: cookie.Value}
|
||||||
if err = db.FetchSession(s); err == nil {
|
if err = sc.Db.FetchSession(s); err == nil {
|
||||||
// session found
|
// session found
|
||||||
u = &db.User{Pubkey: s.Pubkey, LastSeen: time.Now()}
|
u = &db.User{Pubkey: s.Pubkey, LastSeen: time.Now()}
|
||||||
if err = db.UpdateUser(u); err != nil {
|
if err = sc.Db.UpdateUser(u); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
c.Set("session", *u)
|
c.Set("session", *u)
|
||||||
|
@ -38,7 +39,7 @@ func Session(envVars map[string]any) echo.MiddlewareFunc {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func SessionGuard(envVars map[string]any) echo.MiddlewareFunc {
|
func SessionGuard(sc context.ServerContext) echo.MiddlewareFunc {
|
||||||
return func(next echo.HandlerFunc) echo.HandlerFunc {
|
return func(next echo.HandlerFunc) echo.HandlerFunc {
|
||||||
return func(c echo.Context) error {
|
return func(c echo.Context) error {
|
||||||
session := c.Get("session")
|
session := c.Get("session")
|
||||||
|
|
|
@ -3,42 +3,69 @@ package router
|
||||||
import (
|
import (
|
||||||
"github.com/labstack/echo/v4"
|
"github.com/labstack/echo/v4"
|
||||||
|
|
||||||
"git.ekzyis.com/ekzyis/delphi.market/env"
|
"git.ekzyis.com/ekzyis/delphi.market/server/router/context"
|
||||||
"git.ekzyis.com/ekzyis/delphi.market/server/router/handler"
|
"git.ekzyis.com/ekzyis/delphi.market/server/router/handler"
|
||||||
"git.ekzyis.com/ekzyis/delphi.market/server/router/middleware"
|
"git.ekzyis.com/ekzyis/delphi.market/server/router/middleware"
|
||||||
)
|
)
|
||||||
|
|
||||||
func AddRoutes(e *echo.Echo) {
|
type ServerContext = context.ServerContext
|
||||||
envVars := map[string]any{
|
|
||||||
"PUBLIC_URL": env.PublicURL,
|
type MiddlewareFunc func(sc ServerContext) echo.MiddlewareFunc
|
||||||
"COMMIT_SHORT_SHA": env.CommitShortSha,
|
type HandlerFunc = func(sc ServerContext) echo.HandlerFunc
|
||||||
"COMMIT_LONG_SHA": env.CommitLongSha,
|
|
||||||
"VERSION": env.Version,
|
func AddRoutes(e *echo.Echo, sc ServerContext) {
|
||||||
}
|
mountMiddleware(e, sc)
|
||||||
e.Use(middleware.Session(envVars))
|
addFrontendRoutes(e, sc)
|
||||||
e.GET("/", handler.HandleIndex(envVars))
|
addBackendRoutes(e, sc)
|
||||||
e.GET("/login", handler.HandleLogin(envVars))
|
}
|
||||||
e.GET("/api/login", handler.HandleLoginCallback(envVars))
|
|
||||||
e.GET("/api/session", handler.HandleCheckSession(envVars))
|
func mountMiddleware(e *echo.Echo, sc ServerContext) {
|
||||||
e.POST("/logout", handler.HandleLogout(envVars))
|
Use(e, sc, middleware.Session)
|
||||||
e.GET("/user",
|
}
|
||||||
handler.HandleUser(envVars),
|
|
||||||
middleware.SessionGuard(envVars))
|
func addFrontendRoutes(e *echo.Echo, sc ServerContext) {
|
||||||
e.GET("/market/:id",
|
GET(e, sc, "/", handler.HandleIndex)
|
||||||
handler.HandleMarket(envVars),
|
GET(e, sc, "/login", handler.HandleLogin)
|
||||||
middleware.SessionGuard(envVars))
|
POST(e, sc, "/logout", handler.HandleLogout)
|
||||||
e.POST("/market/:id/order",
|
GET(e, sc, "/user",
|
||||||
handler.HandlePostOrder(envVars),
|
handler.HandleUser,
|
||||||
middleware.SessionGuard(envVars),
|
middleware.SessionGuard)
|
||||||
middleware.LNDGuard(envVars))
|
GET(e, sc, "/market/:id",
|
||||||
e.GET("/invoice/:id",
|
handler.HandleMarket,
|
||||||
handler.HandleInvoice(envVars),
|
middleware.SessionGuard)
|
||||||
middleware.SessionGuard(envVars),
|
POST(e, sc, "/market/:id/order",
|
||||||
middleware.LNDGuard(envVars),
|
handler.HandlePostOrder,
|
||||||
)
|
middleware.SessionGuard,
|
||||||
e.GET("/api/invoice/:id",
|
middleware.LNDGuard)
|
||||||
handler.HandleInvoiceAPI(envVars),
|
GET(e, sc, "/invoice/:id",
|
||||||
middleware.SessionGuard(envVars),
|
handler.HandleInvoice,
|
||||||
middleware.LNDGuard(envVars),
|
middleware.SessionGuard)
|
||||||
)
|
}
|
||||||
|
|
||||||
|
func addBackendRoutes(e *echo.Echo, sc ServerContext) {
|
||||||
|
GET(e, sc, "/api/login", handler.HandleLoginCallback)
|
||||||
|
GET(e, sc, "/api/session", handler.HandleCheckSession)
|
||||||
|
GET(e, sc, "/api/invoice/:id",
|
||||||
|
handler.HandleInvoiceAPI,
|
||||||
|
middleware.SessionGuard)
|
||||||
|
}
|
||||||
|
|
||||||
|
func GET(e *echo.Echo, sc ServerContext, path string, scF HandlerFunc, scM ...MiddlewareFunc) *echo.Route {
|
||||||
|
return e.GET(path, scF(sc), toMiddlewareFunc(sc, scM...)...)
|
||||||
|
}
|
||||||
|
|
||||||
|
func POST(e *echo.Echo, sc ServerContext, path string, scF HandlerFunc, scM ...MiddlewareFunc) *echo.Route {
|
||||||
|
return e.POST(path, scF(sc), toMiddlewareFunc(sc, scM...)...)
|
||||||
|
}
|
||||||
|
|
||||||
|
func Use(e *echo.Echo, sc ServerContext, scM ...MiddlewareFunc) {
|
||||||
|
e.Use(toMiddlewareFunc(sc, scM...)...)
|
||||||
|
}
|
||||||
|
|
||||||
|
func toMiddlewareFunc(sc ServerContext, scM ...MiddlewareFunc) []echo.MiddlewareFunc {
|
||||||
|
var m []echo.MiddlewareFunc
|
||||||
|
for _, m_ := range scM {
|
||||||
|
m = append(m, m_(sc))
|
||||||
|
}
|
||||||
|
return m
|
||||||
}
|
}
|
||||||
|
|
|
@ -11,21 +11,25 @@ type Server struct {
|
||||||
*echo.Echo
|
*echo.Echo
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewServer() *Server {
|
type ServerContext = router.ServerContext
|
||||||
e := echo.New()
|
|
||||||
|
|
||||||
|
func New(ctx ServerContext) *Server {
|
||||||
|
var (
|
||||||
|
e *echo.Echo
|
||||||
|
s *Server
|
||||||
|
)
|
||||||
|
e = echo.New()
|
||||||
e.Static("/", "public")
|
e.Static("/", "public")
|
||||||
|
|
||||||
e.Renderer = router.T
|
e.Renderer = router.T
|
||||||
|
|
||||||
router.AddRoutes(e)
|
|
||||||
|
|
||||||
e.Use(middleware.LoggerWithConfig(middleware.LoggerConfig{
|
e.Use(middleware.LoggerWithConfig(middleware.LoggerConfig{
|
||||||
Format: "${time_custom} ${method} ${uri} ${status}\n",
|
Format: "${time_custom} ${method} ${uri} ${status}\n",
|
||||||
CustomTimeFormat: "2006-01-02 15:04:05.00000-0700",
|
CustomTimeFormat: "2006-01-02 15:04:05.00000-0700",
|
||||||
}))
|
}))
|
||||||
|
|
||||||
e.HTTPErrorHandler = httpErrorHandler
|
e.HTTPErrorHandler = httpErrorHandler
|
||||||
|
|
||||||
return &Server{e}
|
s = &Server{e}
|
||||||
|
|
||||||
|
router.AddRoutes(e, ctx)
|
||||||
|
|
||||||
|
return s
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue