134 lines
2.3 KiB
Go
134 lines
2.3 KiB
Go
package main
|
|
|
|
import (
|
|
"context"
|
|
"database/sql"
|
|
"fmt"
|
|
"iter"
|
|
"os"
|
|
"strings"
|
|
"sync"
|
|
|
|
_ "embed"
|
|
|
|
_ "github.com/mattn/go-sqlite3"
|
|
"github.com/uptrace/opentelemetry-go-extra/otelsql"
|
|
semconv "go.opentelemetry.io/otel/semconv/v1.4.0"
|
|
"go.sour.is/xt/internal/otel"
|
|
"go.yarn.social/lextwt"
|
|
"go.yarn.social/types"
|
|
"golang.org/x/sync/errgroup"
|
|
)
|
|
|
|
func run(c *console) error {
|
|
ctx, span := otel.Span(c.Context)
|
|
defer span.End()
|
|
|
|
a := c.Args()
|
|
app := &appState{
|
|
args: a,
|
|
feeds: sync.Map{},
|
|
queue: FibHeap(func(a, b *Feed) bool {
|
|
return a.LastScanOn.Time.Before(b.LastScanOn.Time)
|
|
}),
|
|
}
|
|
|
|
// Setup DB
|
|
err := func(ctx context.Context) error {
|
|
ctx, span := otel.Span(ctx)
|
|
defer span.End()
|
|
|
|
db, err := app.DB()
|
|
if err != nil {
|
|
return err
|
|
}
|
|
defer db.Close()
|
|
|
|
for _, stmt := range strings.Split(initSQL, ";") {
|
|
_, err = db.ExecContext(ctx, stmt)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
}
|
|
|
|
return nil
|
|
}(ctx)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
// Seed File
|
|
err = func(ctx context.Context) error {
|
|
ctx, span := otel.Span(ctx)
|
|
defer span.End()
|
|
|
|
f, err := os.Open(a.baseFeed)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
defer f.Close()
|
|
|
|
twtfile, err := lextwt.ParseFile(f, &types.Twter{
|
|
Nick: a.Nick,
|
|
URI: a.URI,
|
|
})
|
|
if err != nil {
|
|
return fmt.Errorf("%w: %w", ErrParseFailed, err)
|
|
}
|
|
|
|
db, err := app.DB()
|
|
if err != nil {
|
|
return err
|
|
}
|
|
defer db.Close()
|
|
|
|
return storeFeed(ctx, db, twtfile)
|
|
}(ctx)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
wg, ctx := errgroup.WithContext(ctx)
|
|
c.Context = ctx
|
|
|
|
wg.Go(func() error { return refreshLoop(c, app) })
|
|
go httpServer(c, app)
|
|
|
|
wg.Wait()
|
|
return c.Context.Err()
|
|
}
|
|
|
|
type appState struct {
|
|
args args
|
|
feeds sync.Map
|
|
queue *fibHeap[Feed]
|
|
}
|
|
|
|
func (app *appState) DB() (*sql.DB, error) {
|
|
// return sql.Open(app.args.dbtype, app.args.dbfile)
|
|
|
|
return otelsql.Open(app.args.dbtype, app.args.dbfile,
|
|
otelsql.WithAttributes(semconv.DBSystemSqlite),
|
|
otelsql.WithDBName("mydb"))
|
|
}
|
|
|
|
func (app *appState) Feed(feedID string) *Feed {
|
|
return nil
|
|
}
|
|
|
|
func (app *appState) Feeds() iter.Seq2[string, *Feed] {
|
|
return func(yield func(string, *Feed) bool) {
|
|
app.feeds.Range(func(k, v any) bool {
|
|
key, _ := k.(string)
|
|
value, ok := v.(*Feed)
|
|
if !ok {
|
|
return false
|
|
}
|
|
if !yield(key, value) {
|
|
return false
|
|
}
|
|
return true
|
|
})
|
|
}
|
|
}
|