removing old code adopting new architecture

This commit is contained in:
maximo tejeda 2024-04-18 09:33:55 -04:00
parent 7d28c9649a
commit 151c8f7a7b
28 changed files with 263 additions and 843 deletions

View File

@ -1,97 +0,0 @@
package apa
import (
"context"
"fmt"
"log/slog"
"os"
"time"
"github.com/maximotejeda/us_dop_db/db"
"github.com/maximotejeda/us_dop_scrapper/helpers"
"github.com/playwright-community/playwright-go"
)
var (
uri = os.Getenv("APA")
)
func Scrape(ctx context.Context, page playwright.Page, log *slog.Logger) (inst *db.History, err error) {
tout := 120000.00
log = log.With("scrapper", "apap")
if _, err := page.Goto(uri, playwright.PageGotoOptions{
Timeout: &tout,
WaitUntil: playwright.WaitUntilStateLoad,
}); err != nil {
log.Error("could not get info", "error", err)
return nil, err
}
button := page.Locator("#exchangesRates")
button.WaitFor()
button.Click()
compraLocator := page.Locator("#currency-buy-USD")
ventaLocator := page.Locator("#currency-sell-USD")
compraSTR, err := compraLocator.TextContent()
if err != nil {
log.Error("could not get compra str", "err", err)
return nil, err
}
ventaSTR, err := ventaLocator.TextContent()
if err != nil {
log.Error("could not get venta string", "err", err)
return nil, err
}
inst = &db.History{
Name: "asociacion popular de ahorros y prestamos",
Parser: "apap",
Parsed: time.Now().UTC(),
}
inst.Venta = helpers.Normalize(ventaSTR)
inst.Compra = helpers.Normalize(compraSTR)
if inst.Compra == 0 || inst.Venta == 0 {
return nil, fmt.Errorf("apa: institution not parsed: %v", inst)
}
log.Info("parsed", "value", inst)
return inst, nil
}
func ExecParser(
ctx context.Context,
db *db.DB,
browser *playwright.Browser,
log *slog.Logger) (err error) {
t := true
ua := helpers.NewMobileUA()
b := *browser
page, err := b.NewPage(playwright.BrowserNewPageOptions{
UserAgent: &ua,
// IsMobile: &t,
HasTouch: &t,
Viewport: &playwright.Size{
Width: 412,
Height: 915,
},
Screen: &playwright.Size{
Width: 412,
Height: 915,
},
})
if err != nil {
log.Error("creating page", "error", err)
os.Exit(1)
}
ctx, cancel := context.WithTimeout(ctx, 6*time.Minute)
defer page.Close()
defer cancel()
inst, err := Scrape(ctx, page, log)
// here we execute db operations
if err != nil {
return err
}
err = db.Inspect(*inst)
return err
}

Binary file not shown.

Binary file not shown.

View File

@ -1,79 +1,37 @@
package main package main
import ( import (
"context"
"log/slog" "log/slog"
"os"
"os/signal"
"syscall"
"time"
"github.com/maximotejeda/us_dop_db/db" "github.com/maximotejeda/us_dop_scrapper/config"
"github.com/maximotejeda/us_dop_scrapper/apa" "github.com/maximotejeda/us_dop_scrapper/internal/adapters/crawler"
"github.com/maximotejeda/us_dop_scrapper/bcd" dl "github.com/maximotejeda/us_dop_scrapper/internal/adapters/dolar"
"github.com/maximotejeda/us_dop_scrapper/bdr" "github.com/maximotejeda/us_dop_scrapper/internal/application/core/api"
"github.com/maximotejeda/us_dop_scrapper/bhd" "google.golang.org/grpc"
"github.com/maximotejeda/us_dop_scrapper/bnc" "google.golang.org/grpc/credentials/insecure"
"github.com/maximotejeda/us_dop_scrapper/bpd"
"github.com/maximotejeda/us_dop_scrapper/helpers"
"github.com/maximotejeda/us_dop_scrapper/inf"
"github.com/maximotejeda/us_dop_scrapper/scotia"
"github.com/maximotejeda/us_dop_scrapper/vimenca"
"github.com/playwright-community/playwright-go"
) )
func main() { func main() {
var err error log := slog.Default()
dbRoute := os.Getenv("DBURI") var opts []grpc.DialOption
sig := make(chan os.Signal, 1) opts = append(opts, grpc.WithTransportCredentials(insecure.NewCredentials()))
signal.Notify(sig, os.Interrupt, syscall.SIGINT, syscall.SIGTERM, syscall.SIGHUP) conn, err := grpc.Dial(config.GetDollarServiceURL(), opts...)
log := slog.New(slog.NewJSONHandler(os.Stdout, &slog.HandlerOptions{}))
db := db.Dial(dbRoute, log)
// create a chrome and feed parsers
db.CreateTables()
chrome, firefox, webkit := helpers.CreateBrowser(log)
browserList := []*playwright.Browser{chrome, firefox, webkit}
longTick := time.NewTicker(time.Minute * 2)
defer longTick.Stop()
infoTick := time.NewTicker(time.Minute * 1)
defer infoTick.Stop()
ctx, cancel := context.WithCancel(context.Background())
errN := map[string]int{
"bcd": 0,
"bpd": 0,
"apap": 0,
"inf": 0,
}
defer cancel()
who := os.Getenv("WHO")
switch who {
case "bcd":
err = helpers.ExecTask(ctx, db, browserList, log, errN, "bcd", bcd.ExecParser)
case "bpd":
err = helpers.ExecTask(ctx, db, browserList, log, errN, "bpd", bpd.ExecParser)
case "apa":
err = helpers.ExecTask(ctx, db, browserList, log, errN, "apa", apa.ExecParser)
case "brd":
err = helpers.ExecTask(ctx, db, browserList, log, errN, "brd", bdr.ExecParser)
case "bhd":
err = helpers.ExecTask(ctx, db, browserList, log, errN, "bhd", bhd.ExecParser)
case "bnc":
err = helpers.ExecTask(ctx, db, browserList, log, errN, "bnc", bnc.ExecParser)
case "scotia":
err = helpers.ExecTask(ctx, db, browserList, log, errN, "scotia", scotia.ExecParser)
case "vimenca":
err = helpers.ExecTask(ctx, db, browserList, log, errN, "vimenca", vimenca.ExecParser)
default:
err = helpers.ExecTask(ctx, db, browserList, log, errN, "inf", inf.ExecParser)
}
if err != nil { if err != nil {
log.Info("task executed with errors", "name", who, "error", err) log.Error("creating gerpc conn", "error", err)
os.Exit(1) panic(err)
return
} }
log.Info("SUCCESS - task executed", "name", who) defer conn.Close()
os.Exit(0) dol, err := dl.NewAdapter(conn)
if err != nil {
log.Error("creating service adapter", "error", err)
panic(err)
}
crawler, err := crawler.Selector(config.GetWho(), dol)
if err != nil {
log.Error("selecting crawler adapter", "error", err)
panic(err)
}
app := api.NewApplication(crawler)
app.Run()
} }

View File

@ -6,6 +6,10 @@ func GetWho() string {
return getEnvValue("WHO") return getEnvValue("WHO")
} }
func GetDollarServiceURL() string {
return getEnvValue("DOLLAR_SERVICE_URL")
}
func getEnvValue(key string) string { func getEnvValue(key string) string {
if os.Getenv(key) == "" { if os.Getenv(key) == "" {
panic("key not found " + key) panic("key not found " + key)

View File

@ -1,423 +0,0 @@
package db
import (
"database/sql"
_ "embed"
"encoding/json"
"errors"
"fmt"
"log/slog"
"strings"
"time"
"github.com/maximotejeda/us_dop_scrapper/models"
"github.com/maximotejeda/us_dop_scrapper/pub"
_ "modernc.org/sqlite"
)
//go:embed schema.sql
var schema string
type DB struct {
*sql.DB
log *slog.Logger
}
type change struct {
Before models.Institucion `json:"before"`
After models.Institucion `json:"after"`
}
type Message struct {
Message string `json:"message"`
Data change `json:"data"`
Error error `json:"error"`
}
type Institution struct {
ID int
Name string
ShortName string
Created time.Time
}
// Dial
func Dial(path string, log *slog.Logger) *DB {
db, err := sql.Open("sqlite", path)
if err != nil {
fmt.Printf("opening database: %s", err.Error())
panic("opening database")
}
if err := db.Ping(); err != nil {
fmt.Printf("pinging database: %s", err.Error())
panic("pinging database")
}
return &DB{db, log}
}
// Schema
func (db *DB) CreateTables() {
_, err := db.Exec(schema)
if err != nil {
panic(err)
}
}
// Inspect
// Handle behavior of the changes
// Will report errors to a nats consumer
func (db *DB) Inspect(enter models.Institucion) error {
if db == nil {
return fmt.Errorf("nil or empty database")
}
pub, close := pub.Publisher()
defer close()
msg := Message{}
// Get last row added
inst, err := db.GetLatest(enter.Parser, enter.Name)
// if no rows are found because of first enter a name - parser ?
if errors.Is(sql.ErrNoRows, err) {
db.log.Info("adding new item to table: ", "parse", enter.Parser, "name", enter.Name)
msg.Message = "add new institution"
msg.Data.After = enter
data, err := json.Marshal(msg)
if err != nil {
db.log.Error("marshaling struct", "error", err)
}
id, err := db.ADDInstitution(enter.Name)
if err != nil {
return err
}
defer pub("dolar-crawler", data)
return db.AddNew(enter, id)
}
// check prices compra venta
if inst == nil {
db.log.Error("row is nil", "name", enter.Name, "parser", enter.Parser)
return fmt.Errorf("row is nil, not entering row")
}
if enter.Compra == inst.Compra && enter.Venta == inst.Venta {
return nil
} else {
// if one of them changes create a new row
db.log.Info("change registered, adding item", "parse", enter.Parser, "name", enter.Name, "compra enter", enter.Compra, "compra db", inst.Compra, "venta enter", enter.Venta, "venta db", inst.Venta)
msg.Message = "change registered"
msg.Data.After = enter
msg.Data.Before = *inst
data, err := json.Marshal(msg)
if err != nil {
db.log.Error("marshaling struct", "error", err)
}
ins, err := db.GETInstitution(enter.Name)
if err != nil {
return err
}
defer pub("dolar-crawler", data)
return db.AddNew(enter, int64(ins.ID))
}
}
// GetLatest
// returns the latest row in a specific parser and name
// we are using DateTime in DB and date.Datetime in go
func (db *DB) GetLatest(parser string, name string) (inst *models.Institucion, err error) {
var parsed string
inst = &models.Institucion{}
stmtt, err := db.Prepare("SELECT i.name, d.parser, d.compra, d.venta, d.parsed FROM dolars AS d JOIN institutions as i ON d.name_id = i.id WHERE d.parser = ? AND i.name = ? ORDER BY d.parsed DESC LIMIT 1;")
if err != nil {
db.log.Error("preparing stmtt", "error", err.Error())
return nil, err
}
defer stmtt.Close()
if err := stmtt.QueryRow(parser, name).Scan(&inst.Name, &inst.Parser, &inst.Compra, &inst.Venta, &parsed); err != nil {
db.log.Error("getting latest", "error", err.Error(), "parser", parser, "name", name)
return nil, err
}
inst.Parsed, err = time.Parse(time.DateTime, parsed)
if err != nil {
//db.log.Error("parsed", "error", err.Error())
return nil, err
}
return inst, nil
}
// AddNew
// Add a new row in the dolar table
// Will send to nats changes on prices
func (db *DB) AddNew(row models.Institucion, id int64) error {
stmt, err := db.Prepare("INSERT INTO dolars (name_id, compra, venta, parser, parsed) VALUES(?,?,?,?,?);")
if err != nil {
return err
}
defer stmt.Close()
parsed := row.Parsed.Format(time.DateTime)
_, err = stmt.Exec(&id, &row.Compra, &row.Venta, &row.Parser, &parsed)
if err != nil {
return err
}
return nil
}
func (db *DB) ADDInstitution(name string) (id int64, err error) {
stmt, err := db.Prepare("INSERT INTO institutions (name, short_name, created) VALUES(?,?,?);")
if err != nil {
return 0, err
}
defer stmt.Close()
parsed := time.Now().Format(time.DateTime)
short := shortner(name)
res, err := stmt.Exec(&name, short, &parsed)
if err != nil {
return 0, err
}
id, err = res.LastInsertId()
if err != nil {
return 0, err
}
return id, nil
}
func (db *DB) GETInstitution(name string) (inst *Institution, err error) {
institution := Institution{}
stmtt, err := db.Prepare("SELECT id, name, short_name FROM institutions WHERE name = ?")
if err != nil {
db.log.Error("preparing stmt", "error", err.Error())
return nil, err
}
defer stmtt.Close()
if err := stmtt.QueryRow(name).Scan(&institution.ID, &institution.Name, &institution.ShortName); err != nil {
db.log.Error("getting institution", "error", err.Error(), "short name", institution.ShortName, "name", name)
return nil, err
}
return inst, err
}
func (db *DB) GetAll() ([]string, error) {
stmt, err := db.Prepare("SELECT i.name FROM institutions AS i;")
if err != nil {
db.log.Error("[db-GetAll]", "error", err)
return nil, err
}
rows, err := stmt.Query()
if err != nil {
db.log.Error("[db-GetAll-stmt]", "error", err)
return nil, err
}
defer rows.Close()
insts := []string{}
for rows.Next() {
inst := ""
if err = rows.Scan(&inst); err != nil {
return nil, err
}
if inst == "" {
continue
}
insts = append(insts, inst)
}
if err := rows.Err(); err != nil {
return insts, err
}
return insts, nil
}
func (db *DB) GetBancos() ([]string, error) {
stmt, err := db.Prepare("SELECT i.name FROM institutions AS i WHERE i.name LIKE '%ban%' OR i.name LIKE '%scoti%'")
if err != nil {
db.log.Error("[inst-GetAll]", "error", err)
return nil, err
}
rows, err := stmt.Query()
if err != nil {
db.log.Error("[inst-GetAll-stmt]", "error", err)
return nil, err
}
defer rows.Close()
insts := []string{}
for rows.Next() {
inst := ""
if err = rows.Scan(&inst); err != nil {
return nil, err
}
if inst == "" {
continue
}
insts = append(insts, inst)
}
if err := rows.Err(); err != nil {
return insts, err
}
return insts, nil
}
func (db *DB) GetCajas() ([]string, error) {
stmt, err := db.Prepare("SELECT i.name FROM institutions AS i WHERE i.name LIKE '%asociacion%'")
if err != nil {
db.log.Error("[inst-GetAll]", "error", err)
return nil, err
}
rows, err := stmt.Query()
if err != nil {
db.log.Error("[inst-GetAll-stmt]", "error", err)
return nil, err
}
defer rows.Close()
insts := []string{}
for rows.Next() {
inst := ""
if err = rows.Scan(&inst); err != nil {
return nil, err
}
if inst == "" {
continue
}
insts = append(insts, inst)
}
if err := rows.Err(); err != nil {
return insts, err
}
return insts, nil
}
func (db *DB) GetAgentes() ([]string, error) {
stmt, err := db.Prepare("SELECT i.name FROM institutions AS i WHERE i.name NOT LIKE '%ban%' AND i.name NOT LIKE '%scoti%' AND i.name NOT LIKE '%asociacion%'")
if err != nil {
db.log.Error("[inst-GetAll]", "error", err)
return nil, err
}
rows, err := stmt.Query()
if err != nil {
db.log.Error("[inst-GetAll-stmt]", "error", err)
return nil, err
}
defer rows.Close()
insts := []string{}
for rows.Next() {
inst := ""
if err = rows.Scan(&inst); err != nil {
return nil, err
}
if inst == "" {
continue
}
insts = append(insts, inst)
}
if err := rows.Err(); err != nil {
return insts, err
}
return insts, nil
}
func (db *DB) GetLastPrice(name string) (inst *models.Institucion, err error) {
var parsed string
inst = &models.Institucion{}
stmt, err := db.Prepare("SELECT i.name, d.parser, d.compra, d.venta, d.parsed FROM dolars AS d JOIN institutions as i ON d.name_id = i.id WHERE name = ? ORDER BY parsed DESC LIMIT 1;")
if err != nil {
db.log.Error("preparing", "error", err.Error())
return nil, err
}
defer stmt.Close()
if err := stmt.QueryRow(name).Scan(&inst.Name, &inst.Parser, &inst.Compra, &inst.Venta, &parsed); err != nil {
db.log.Error("getting last price", "error", err.Error(), "name", name)
return nil, err
}
inst.Parsed, err = time.Parse(time.DateTime, parsed)
if err != nil {
//db.log.Error("parsed", "error", err.Error())
return nil, err
}
return inst, nil
}
func (db *DB) GetChangeSince(name string, duration time.Duration) (insts []*models.Institucion, err error) {
date := time.Now().Add(-duration).Format(time.DateTime)
stmt, err := db.Prepare("SELECT i.name, d.parser, d.compra, d.venta, d.parsed FROM dolars AS d JOIN institutions as i ON d.name_id = i.id WHERE name = ? AND parsed > ? ORDER BY parsed DESC;")
if err != nil {
db.log.Error("[GetChangeSince] preparing", "error", err.Error())
return nil, err
}
defer stmt.Close()
rows, err := stmt.Query(name, date)
if err != nil {
db.log.Error("[GetChangeSince] preparing", "error", err.Error())
return nil, err
}
defer rows.Close()
for rows.Next() {
inst := models.Institucion{}
parsed := ""
if err := rows.Scan(&inst.Name, &inst.Parser, &inst.Compra, &inst.Venta, &parsed); err != nil {
db.log.Error("[GetChangeSince] scanning", "error", err)
return nil, err
}
inst.Parsed, err = time.Parse(time.DateTime, parsed)
if err != nil {
//db.log.Error("parsed", "error", err.Error())
continue
}
insts = append(insts, &inst)
}
return insts, nil
}
func shortner(name string) string {
if name == "" {
return ""
}
switch strings.ToLower(name) {
case "banco popular":
return "bpd"
case "banreservas":
return "brd"
case "banco central dominicano":
return "bcd"
case "banco hipotecario dominicano":
return "bhd"
case "asociacion popular de ahorros y prestamos":
return "apap"
case "asociacion cibao de ahorros y prestamos":
return "acap"
case "asociacion la nacional de ahorros y prestamos":
return "alnap"
case "asociacion peravia de ahorros y prestamos":
return "apeap"
case "banco santa cruz":
return "bsc"
case "imbert y balbuena":
return "imb"
case "banco activo dominicana":
return "bacd"
case "scotiabank cambio online":
return "scline"
case "banco lopez de haro":
return "blh"
}
nameList := strings.Split(name, " ")
switch len(nameList) {
case 1:
return nameList[0]
case 2:
return string(nameList[0][0]) + nameList[1][0:2]
case 3:
return string(nameList[0][0] + nameList[1][0] + nameList[2][0])
default:
return "n/a"
}
}

View File

@ -1,18 +0,0 @@
PRAGMA foreign_keys = ON;
CREATE TABLE IF NOT EXISTS 'dolars' (
id INTEGER PRIMARY KEY,
name_id INTEGER NOT NULL,
compra REAL NOT NULL,
venta REAL NOT NULL,
parser TEXT NOT NULL,
parsed TEXT NOT NULL,
FOREIGN KEY(name_id) REFERENCES institutions(id) ON DELETE CASCADE
);
CREATE TABLE IF NOT EXISTS 'institutions' (
id INTEGER PRIMARY KEY,
name TEXT NOT NULL,
short_name TEXT NOT NULL,
created TEXT NOT NULL
);

View File

@ -1 +0,0 @@
maximo@debian-pc.9800:1713363571

View File

@ -162,7 +162,6 @@ func CreateBrowser(log *slog.Logger) (chrome *playwright.Browser, firefox *playw
// ExecTask // ExecTask
func ExecTask( func ExecTask(
ctx context.Context, ctx context.Context,
dbi *db.DB, dbi *db.DB,
browser []*playwright.Browser, browser []*playwright.Browser,
log *slog.Logger, log *slog.Logger,

View File

@ -1 +0,0 @@
package inf

View File

@ -13,19 +13,17 @@ import (
"github.com/playwright-community/playwright-go" "github.com/playwright-community/playwright-go"
) )
var (
uri = os.Getenv("APA")
)
type Apap struct { type Apap struct {
client ports.DollarPort
} }
func NewApap() ports.APIPorts { func NewApap(client ports.DollarPort) ports.APIPorts {
return &Apap{} return &Apap{client: client}
} }
func (a Apap) Scrape(ctx context.Context, page playwright.Page, log *slog.Logger) (insts []*domain.History, err error) { func (a Apap) Scrape(ctx context.Context, page playwright.Page, log *slog.Logger) (insts []*domain.History, err error) {
tout := 120000.00 tout := 120000.00
uri := os.Getenv("APA")
log = log.With("scrapper", "apap") log = log.With("scrapper", "apap")
if _, err := page.Goto(uri, playwright.PageGotoOptions{ if _, err := page.Goto(uri, playwright.PageGotoOptions{
Timeout: &tout, Timeout: &tout,
@ -95,10 +93,14 @@ func (a Apap) ExecParser(
ctx, cancel := context.WithTimeout(ctx, 6*time.Minute) ctx, cancel := context.WithTimeout(ctx, 6*time.Minute)
defer page.Close() defer page.Close()
defer cancel() defer cancel()
_, err = a.Scrape(ctx, page, log) histList, err := a.Scrape(ctx, page, log)
// here we execute db operations // here we execute db operations
if err != nil { if err != nil {
return err return err
} }
err = a.client.NewHistory(histList[0])
if err != nil {
return err
}
return err return err
} }

View File

@ -1,4 +1,4 @@
package bcd package crawler
import ( import (
"context" "context"
@ -7,23 +7,26 @@ import (
"os" "os"
"time" "time"
"github.com/maximotejeda/us_dop_db/db"
"github.com/maximotejeda/us_dop_scrapper/helpers" "github.com/maximotejeda/us_dop_scrapper/helpers"
"github.com/maximotejeda/us_dop_scrapper/models" "github.com/maximotejeda/us_dop_scrapper/internal/application/core/domain"
"github.com/maximotejeda/us_dop_scrapper/internal/ports"
"github.com/playwright-community/playwright-go" "github.com/playwright-community/playwright-go"
) )
type bcd struct { type bcd struct {
models.Institucion client ports.DollarPort
} }
var ( func NewBCD(client ports.DollarPort) ports.APIPorts {
uri = os.Getenv("BCD") return &bcd{
) client: client,
}
}
func Scrape(ctx context.Context, page playwright.Page, log *slog.Logger) (inst *db.History, err error) { func (b bcd) Scrape(ctx context.Context, page playwright.Page, log *slog.Logger) (insts []*domain.History, err error) {
log = log.With("scrapper", "bcd") log = log.With("scrapper", "bcd")
tout := 90000.00 tout := 90000.00
uri := os.Getenv("BCD")
if _, err = page.Goto(uri, playwright.PageGotoOptions{ if _, err = page.Goto(uri, playwright.PageGotoOptions{
Timeout: &tout, Timeout: &tout,
WaitUntil: playwright.WaitUntilStateLoad, WaitUntil: playwright.WaitUntilStateLoad,
@ -51,10 +54,10 @@ func Scrape(ctx context.Context, page playwright.Page, log *slog.Logger) (inst *
return nil, err return nil, err
} }
inst = &db.History{ inst := &domain.History{
Parser: "bcd", Parser: "bcd",
Name: "banco central dominicano", Name: "banco central dominicano",
Parsed: time.Now().UTC(), Parsed: time.Now().Unix(),
} }
inst.Compra = helpers.Normalize(compra) inst.Compra = helpers.Normalize(compra)
@ -63,12 +66,11 @@ func Scrape(ctx context.Context, page playwright.Page, log *slog.Logger) (inst *
if inst.Compra == 0 || inst.Venta == 0 { if inst.Compra == 0 || inst.Venta == 0 {
return nil, fmt.Errorf("bcd: institution not parsed compra or venta cant be 0") return nil, fmt.Errorf("bcd: institution not parsed compra or venta cant be 0")
} }
return inst, nil return []*domain.History{inst}, nil
} }
func ExecParser( func (bc bcd) ExecParser(
ctx context.Context, ctx context.Context,
db *db.DB,
browser *playwright.Browser, browser *playwright.Browser,
log *slog.Logger) (err error) { log *slog.Logger) (err error) {
t := true t := true
@ -94,11 +96,15 @@ func ExecParser(
ctx, cancel := context.WithTimeout(ctx, 6*time.Minute) ctx, cancel := context.WithTimeout(ctx, 6*time.Minute)
defer page.Close() defer page.Close()
defer cancel() defer cancel()
inst, err := Scrape(ctx, page, log) inst, err := bc.Scrape(ctx, page, log)
if err != nil {
return err
}
err = bc.client.NewHistory(inst[0])
if err != nil { if err != nil {
return err return err
} }
err = db.Inspect(*inst)
return err return err
} }

View File

@ -1,4 +1,4 @@
package bdr package crawler
import ( import (
"context" "context"
@ -7,18 +7,25 @@ import (
"os" "os"
"time" "time"
"github.com/maximotejeda/us_dop_db/db"
"github.com/maximotejeda/us_dop_scrapper/helpers" "github.com/maximotejeda/us_dop_scrapper/helpers"
"github.com/maximotejeda/us_dop_scrapper/internal/application/core/domain"
"github.com/maximotejeda/us_dop_scrapper/internal/ports"
"github.com/playwright-community/playwright-go" "github.com/playwright-community/playwright-go"
) )
var ( type bdr struct {
uri = os.Getenv("BDR") client ports.DollarPort
) }
func Scrape(ctx context.Context, page playwright.Page, log *slog.Logger) (inst *db.History, err error) { func NewBDR(client ports.DollarPort) ports.APIPorts {
return &bdr{
client: client,
}
}
func (bd bdr) Scrape(ctx context.Context, page playwright.Page, log *slog.Logger) (insts []*domain.History, err error) {
tout := 120000.00 tout := 120000.00
log = log.With("scrapper", "bdr") log = log.With("scrapper", "bdr")
uri := os.Getenv("BDR")
if _, err := page.Goto(uri, playwright.PageGotoOptions{ if _, err := page.Goto(uri, playwright.PageGotoOptions{
Timeout: &tout, Timeout: &tout,
WaitUntil: playwright.WaitUntilStateLoad, WaitUntil: playwright.WaitUntilStateLoad,
@ -47,10 +54,10 @@ func Scrape(ctx context.Context, page playwright.Page, log *slog.Logger) (inst *
log.Error("parsing compra", "err", err) log.Error("parsing compra", "err", err)
return nil, err return nil, err
} }
inst = &db.History{ inst := &domain.History{
Name: "banreservas", Name: "banreservas",
Parser: "brd", Parser: "brd",
Parsed: time.Now().UTC(), Parsed: time.Now().Unix(),
} }
compra := helpers.Normalize(compraSTR) compra := helpers.Normalize(compraSTR)
@ -62,13 +69,12 @@ func Scrape(ctx context.Context, page playwright.Page, log *slog.Logger) (inst *
if inst.Compra == 0 || inst.Venta == 0 { if inst.Compra == 0 || inst.Venta == 0 {
return nil, fmt.Errorf("brd: institution not parsed") return nil, fmt.Errorf("brd: institution not parsed")
} }
insts = append(insts, inst)
return inst, nil return insts, nil
} }
func ExecParser( func (bd bdr) ExecParser(
ctx context.Context, ctx context.Context,
db *db.DB,
browser *playwright.Browser, browser *playwright.Browser,
log *slog.Logger) (err error) { log *slog.Logger) (err error) {
t := true t := true
@ -94,11 +100,11 @@ func ExecParser(
ctx, cancel := context.WithTimeout(ctx, 6*time.Minute) ctx, cancel := context.WithTimeout(ctx, 6*time.Minute)
defer page.Close() defer page.Close()
defer cancel() defer cancel()
inst, err := Scrape(ctx, page, log) insts, err := bd.Scrape(ctx, page, log)
if err != nil { if err != nil {
return err return err
} }
err = db.Inspect(*inst) err = bd.client.NewHistory(insts[0])
return err return err
} }

View File

@ -1,4 +1,4 @@
package bhd package crawler
import ( import (
"context" "context"
@ -8,19 +8,27 @@ import (
"strings" "strings"
"time" "time"
"github.com/maximotejeda/us_dop_db/db"
"github.com/maximotejeda/us_dop_scrapper/helpers" "github.com/maximotejeda/us_dop_scrapper/helpers"
"github.com/maximotejeda/us_dop_scrapper/internal/application/core/domain"
"github.com/maximotejeda/us_dop_scrapper/internal/ports"
"github.com/playwright-community/playwright-go" "github.com/playwright-community/playwright-go"
) )
var ( type bhd struct {
uri = os.Getenv("BHD") client ports.DollarPort
) }
func NewBHD(client ports.DollarPort) ports.APIPorts {
return &bhd{
client: client,
}
}
// Scrape // Scrape
// needs a mobile User Agent // needs a mobile User Agent
func Scrape(ctx context.Context, page playwright.Page, log *slog.Logger) (inst *db.History, err error) { func (bh bhd) Scrape(ctx context.Context, page playwright.Page, log *slog.Logger) (insts []*domain.History, err error) {
tout := 120000.00 tout := 120000.00
uri := os.Getenv("BHD")
log = log.With("scrapper", "bhd") log = log.With("scrapper", "bhd")
if _, err := page.Goto(uri, playwright.PageGotoOptions{ if _, err := page.Goto(uri, playwright.PageGotoOptions{
Timeout: &tout, Timeout: &tout,
@ -51,10 +59,10 @@ func Scrape(ctx context.Context, page playwright.Page, log *slog.Logger) (inst *
return nil, err return nil, err
} }
inst = &db.History{ inst := &domain.History{
Name: "banco hipotecario dominicano", Name: "banco hipotecario dominicano",
Parser: "bhd", Parser: "bhd",
Parsed: time.Now().UTC(), Parsed: time.Now().Unix(),
} }
for _, it := range fieldGroup { for _, it := range fieldGroup {
@ -101,12 +109,11 @@ func Scrape(ctx context.Context, page playwright.Page, log *slog.Logger) (inst *
return nil, fmt.Errorf("bhd: institution not parsed: %v", inst) return nil, fmt.Errorf("bhd: institution not parsed: %v", inst)
} }
//log.Info(fmt.Sprintf("%v", inst)) //log.Info(fmt.Sprintf("%v", inst))
return inst, nil return []*domain.History{inst}, nil
} }
func ExecParser( func (bh bhd) ExecParser(
ctx context.Context, ctx context.Context,
db *db.DB,
browser *playwright.Browser, browser *playwright.Browser,
log *slog.Logger) (err error) { log *slog.Logger) (err error) {
t := true t := true
@ -132,10 +139,10 @@ func ExecParser(
ctx, cancel := context.WithTimeout(ctx, 6*time.Minute) ctx, cancel := context.WithTimeout(ctx, 6*time.Minute)
defer page.Close() defer page.Close()
defer cancel() defer cancel()
inst, err := Scrape(ctx, page, log) inst, err := bh.Scrape(ctx, page, log)
if err != nil { if err != nil {
return err return err
} }
err = db.Inspect(*inst) bh.client.NewHistory(inst[0])
return err return err
} }

View File

@ -1,4 +1,4 @@
package bnc package crawler
import ( import (
"context" "context"
@ -7,17 +7,25 @@ import (
"os" "os"
"time" "time"
"github.com/maximotejeda/us_dop_db/db"
"github.com/maximotejeda/us_dop_scrapper/helpers" "github.com/maximotejeda/us_dop_scrapper/helpers"
"github.com/maximotejeda/us_dop_scrapper/internal/application/core/domain"
"github.com/maximotejeda/us_dop_scrapper/internal/ports"
"github.com/playwright-community/playwright-go" "github.com/playwright-community/playwright-go"
) )
var ( type bnc struct {
uri = os.Getenv("BNC") client ports.DollarPort
) }
func Scrape(ctx context.Context, page playwright.Page, log *slog.Logger) (inst *db.History, err error) { func NewBNC(client ports.DollarPort) ports.APIPorts {
return &bnc{
client: client,
}
}
func (bn bnc) Scrape(ctx context.Context, page playwright.Page, log *slog.Logger) (insts []*domain.History, err error) {
tout := 120000.00 tout := 120000.00
uri := os.Getenv("BNC")
log = log.With("scrapper", "bnc") log = log.With("scrapper", "bnc")
if _, err := page.Goto(uri, playwright.PageGotoOptions{ if _, err := page.Goto(uri, playwright.PageGotoOptions{
Timeout: &tout, Timeout: &tout,
@ -44,10 +52,10 @@ func Scrape(ctx context.Context, page playwright.Page, log *slog.Logger) (inst *
log.Error("could not get venta string", "err", err) log.Error("could not get venta string", "err", err)
return nil, err return nil, err
} }
inst = &db.History{ inst := &domain.History{
Name: "banesco", Name: "banesco",
Parser: "bnc", Parser: "bnc",
Parsed: time.Now().UTC(), Parsed: time.Now().Unix(),
} }
inst.Venta = helpers.Normalize(ventaSTR) inst.Venta = helpers.Normalize(ventaSTR)
@ -56,12 +64,11 @@ func Scrape(ctx context.Context, page playwright.Page, log *slog.Logger) (inst *
if inst.Compra == 0 || inst.Venta == 0 { if inst.Compra == 0 || inst.Venta == 0 {
return nil, fmt.Errorf("bnc: institution not parsed: %v", inst) return nil, fmt.Errorf("bnc: institution not parsed: %v", inst)
} }
return inst, nil return []*domain.History{inst}, nil
} }
func ExecParser( func (bn bnc) ExecParser(
ctx context.Context, ctx context.Context,
db *db.DB,
browser *playwright.Browser, browser *playwright.Browser,
log *slog.Logger) (err error) { log *slog.Logger) (err error) {
t := true t := true
@ -87,11 +94,11 @@ func ExecParser(
ctx, cancel := context.WithTimeout(ctx, 6*time.Minute) ctx, cancel := context.WithTimeout(ctx, 6*time.Minute)
defer page.Close() defer page.Close()
defer cancel() defer cancel()
inst, err := Scrape(ctx, page, log) inst, err := bn.Scrape(ctx, page, log)
// here we execute db operations // here we execute db operations
if err != nil { if err != nil {
return err return err
} }
err = db.Inspect(*inst) bn.client.NewHistory(inst[0])
return err return err
} }

View File

@ -1,4 +1,4 @@
package bpd package crawler
import ( import (
"context" "context"
@ -8,21 +8,29 @@ import (
"strconv" "strconv"
"time" "time"
"github.com/maximotejeda/us_dop_db/db"
"github.com/maximotejeda/us_dop_scrapper/helpers" "github.com/maximotejeda/us_dop_scrapper/helpers"
"github.com/maximotejeda/us_dop_scrapper/internal/application/core/domain"
"github.com/maximotejeda/us_dop_scrapper/internal/ports"
"github.com/playwright-community/playwright-go" "github.com/playwright-community/playwright-go"
) )
var ( type bpd struct {
uri = os.Getenv("BPD") client ports.DollarPort
) }
func NewBPD(client ports.DollarPort) ports.APIPorts {
return &bpd{
client: client,
}
}
// Scrape // Scrape
// needs a mobile User Agent // needs a mobile User Agent
func Scrape(ctx context.Context, page playwright.Page, log *slog.Logger) (inst *db.History, err error) { func (bp bpd) Scrape(ctx context.Context, page playwright.Page, log *slog.Logger) (insts []*domain.History, err error) {
tout := 120000.00 tout := 120000.00
//start := time.Now()
uri := os.Getenv("BPD")
log = log.With("scrapper", "bpd") log = log.With("scrapper", "bpd")
if _, err := page.Goto(uri, playwright.PageGotoOptions{ if _, err := page.Goto(uri, playwright.PageGotoOptions{
Timeout: &tout, Timeout: &tout,
@ -54,10 +62,10 @@ func Scrape(ctx context.Context, page playwright.Page, log *slog.Logger) (inst *
log.Error("compra value", "err", err) log.Error("compra value", "err", err)
return nil, err return nil, err
} }
inst = &db.History{ inst := &domain.History{
Name: "banco popular", Name: "banco popular",
Parser: "bpd", Parser: "bpd",
Parsed: time.Now().UTC(), Parsed: time.Now().Unix(),
} }
compra, err := strconv.ParseFloat(compraSTR, 64) compra, err := strconv.ParseFloat(compraSTR, 64)
if err != nil { if err != nil {
@ -75,7 +83,7 @@ func Scrape(ctx context.Context, page playwright.Page, log *slog.Logger) (inst *
if inst.Compra == 0 || inst.Venta == 0 { if inst.Compra == 0 || inst.Venta == 0 {
return nil, fmt.Errorf("bpd: institution not parsed") return nil, fmt.Errorf("bpd: institution not parsed")
} }
return inst, nil return []*domain.History{inst}, nil
} }
func HoverTasas(page playwright.Page) { func HoverTasas(page playwright.Page) {
@ -83,9 +91,8 @@ func HoverTasas(page playwright.Page) {
tasasMenu.Hover() tasasMenu.Hover()
} }
func ExecParser( func (bp bpd) ExecParser(
ctx context.Context, ctx context.Context,
db *db.DB,
browser *playwright.Browser, browser *playwright.Browser,
log *slog.Logger) (err error) { log *slog.Logger) (err error) {
t := true t := true
@ -111,10 +118,10 @@ func ExecParser(
ctx, cancel := context.WithTimeout(ctx, 6*time.Minute) ctx, cancel := context.WithTimeout(ctx, 6*time.Minute)
defer page.Close() defer page.Close()
defer cancel() defer cancel()
inst, err := Scrape(ctx, page, log) inst, err := bp.Scrape(ctx, page, log)
if err != nil { if err != nil {
return err return err
} }
err = db.Inspect(*inst) bp.client.NewHistory(inst[0])
return err return err
} }

View File

@ -6,11 +6,27 @@ import (
"github.com/maximotejeda/us_dop_scrapper/internal/ports" "github.com/maximotejeda/us_dop_scrapper/internal/ports"
) )
func Selector(who string) (ports.APIPorts, error) { func Selector(who string, client ports.DollarPort) (ports.APIPorts, error) {
var parser ports.APIPorts var parser ports.APIPorts
switch who { switch who {
case "apap": case "apap":
parser = NewApap() parser = NewApap(client)
case "bcd":
parser = NewBCD(client)
case "bdr":
parser = NewBDR(client)
case "bhd":
parser = NewBHD(client)
case "bnc":
parser = NewBNC(client)
case "bpd":
parser = NewBPD(client)
case "inf":
parser = NewINF(client)
case "scotia":
parser = NewScotia(client)
case "vimenca":
parser = NewVimenca(client)
default: default:
return nil, fmt.Errorf("not recognize who: " + who) return nil, fmt.Errorf("not recognize who: " + who)
} }

View File

@ -1,4 +1,4 @@
package inf package crawler
import ( import (
"context" "context"
@ -8,17 +8,25 @@ import (
"strings" "strings"
"time" "time"
"github.com/maximotejeda/us_dop_db/db"
"github.com/maximotejeda/us_dop_scrapper/helpers" "github.com/maximotejeda/us_dop_scrapper/helpers"
"github.com/maximotejeda/us_dop_scrapper/internal/application/core/domain"
"github.com/maximotejeda/us_dop_scrapper/internal/ports"
"github.com/playwright-community/playwright-go" "github.com/playwright-community/playwright-go"
) )
var ( type inf struct {
uri = os.Getenv("GENERAL") client ports.DollarPort
) }
func NewINF(client ports.DollarPort) ports.APIPorts {
return &inf{
client: client,
}
}
// Scrape // Scrape
func Scrape(ctx context.Context, page playwright.Page, log *slog.Logger) (instList []*db.History, err error) { func (in inf) Scrape(ctx context.Context, page playwright.Page, log *slog.Logger) (instList []*domain.History, err error) {
uri := os.Getenv("GENERAL")
log = log.With("scrapper", "general") log = log.With("scrapper", "general")
tout := float64(120000) tout := float64(120000)
if _, err := page.Goto(uri, playwright.PageGotoOptions{ if _, err := page.Goto(uri, playwright.PageGotoOptions{
@ -42,9 +50,9 @@ func Scrape(ctx context.Context, page playwright.Page, log *slog.Logger) (instLi
return nil, err return nil, err
} }
scotia := false // in this page there are 2 scotia one the change online the other is tha bank scotia := false // in this page there are 2 scotia one the change online the other is tha bank
instList = []*db.History{} instList = []*domain.History{}
for _, entry := range entries { for _, entry := range entries {
inst := &db.History{ inst := &domain.History{
Parser: "inf", Parser: "inf",
} }
title, _ := entry.Locator("span.nombre").TextContent() title, _ := entry.Locator("span.nombre").TextContent()
@ -67,7 +75,7 @@ func Scrape(ctx context.Context, page playwright.Page, log *slog.Logger) (instLi
inst.Compra = helpers.Normalize(compra) inst.Compra = helpers.Normalize(compra)
inst.Venta = helpers.Normalize(venta) inst.Venta = helpers.Normalize(venta)
inst.Parsed = time.Now().UTC() inst.Parsed = time.Now().Unix()
// if one of the inst has 0 on the sell/buy dont process it // if one of the inst has 0 on the sell/buy dont process it
if inst.Compra == 0 || inst.Venta == 0 { if inst.Compra == 0 || inst.Venta == 0 {
log.Warn("skipping", "nombre", inst.Name, "compra", inst.Compra, "venta", inst.Venta) log.Warn("skipping", "nombre", inst.Name, "compra", inst.Compra, "venta", inst.Venta)
@ -92,9 +100,8 @@ func getValue(place playwright.Locator) string {
} }
// ExecParser // ExecParser
func ExecParser( func (in inf) ExecParser(
ctx context.Context, ctx context.Context,
db *db.DB,
browser *playwright.Browser, browser *playwright.Browser,
log *slog.Logger) error { log *slog.Logger) error {
t := true t := true
@ -120,13 +127,13 @@ func ExecParser(
ctx, cancel := context.WithTimeout(ctx, 6*time.Minute) ctx, cancel := context.WithTimeout(ctx, 6*time.Minute)
defer page.Close() defer page.Close()
defer cancel() defer cancel()
instList, err := Scrape(ctx, page, log) instList, err := in.Scrape(ctx, page, log)
if err != nil { if err != nil {
return err return err
} }
for _, inst := range instList { for _, inst := range instList {
log.Info("processing", "name", inst.Name) log.Info("processing", "name", inst.Name)
err = db.Inspect(*inst) err = in.client.NewHistory(inst)
if err != nil { if err != nil {
log.Error(fmt.Sprintf("inspecting %s", inst.Name), "error", err) log.Error(fmt.Sprintf("inspecting %s", inst.Name), "error", err)
} }

View File

@ -1,4 +1,4 @@
package scotia package crawler
import ( import (
"context" "context"
@ -7,17 +7,25 @@ import (
"os" "os"
"time" "time"
"github.com/maximotejeda/us_dop_db/db"
"github.com/maximotejeda/us_dop_scrapper/helpers" "github.com/maximotejeda/us_dop_scrapper/helpers"
"github.com/maximotejeda/us_dop_scrapper/internal/application/core/domain"
"github.com/maximotejeda/us_dop_scrapper/internal/ports"
"github.com/playwright-community/playwright-go" "github.com/playwright-community/playwright-go"
) )
var ( type scotia struct {
uri = os.Getenv("SCOTIA") client ports.DollarPort
) }
func Scrape(ctx context.Context, page playwright.Page, log *slog.Logger) (insts []*db.History, err error) { func NewScotia(client ports.DollarPort) ports.APIPorts {
return &scotia{
client: client,
}
}
func (sct scotia) Scrape(ctx context.Context, page playwright.Page, log *slog.Logger) (insts []*domain.History, err error) {
tout := 120000.00 tout := 120000.00
uri := os.Getenv("SCOTIA")
log = log.With("scrapper", "scotia") log = log.With("scrapper", "scotia")
if _, err := page.Goto(uri, playwright.PageGotoOptions{ if _, err := page.Goto(uri, playwright.PageGotoOptions{
Timeout: &tout, Timeout: &tout,
@ -55,10 +63,10 @@ func Scrape(ctx context.Context, page playwright.Page, log *slog.Logger) (insts
log.Error("could not get venta string", "err", err) log.Error("could not get venta string", "err", err)
return nil, err return nil, err
} }
instOnsite := &db.History{ instOnsite := &domain.History{
Name: "scotiabank", Name: "scotiabank",
Parser: "scotia", Parser: "scotia",
Parsed: time.Now().UTC(), Parsed: time.Now().Unix(),
} }
instOnsite.Venta = helpers.Normalize(ventaOnsiteSTR) instOnsite.Venta = helpers.Normalize(ventaOnsiteSTR)
@ -79,10 +87,10 @@ func Scrape(ctx context.Context, page playwright.Page, log *slog.Logger) (insts
return nil, err return nil, err
} }
instOnline := &db.History{ instOnline := &domain.History{
Name: "scotiabank cambio online", Name: "scotiabank cambio online",
Parser: "scotia", Parser: "scotia",
Parsed: time.Now().UTC(), Parsed: time.Now().Unix(),
} }
instOnline.Venta = helpers.Normalize(ventaOnlineSTR) instOnline.Venta = helpers.Normalize(ventaOnlineSTR)
instOnline.Compra = helpers.Normalize(compraOnlineSTR) instOnline.Compra = helpers.Normalize(compraOnlineSTR)
@ -95,9 +103,8 @@ func Scrape(ctx context.Context, page playwright.Page, log *slog.Logger) (insts
return insts, nil return insts, nil
} }
func ExecParser( func (sct scotia) ExecParser(
ctx context.Context, ctx context.Context,
db *db.DB,
browser *playwright.Browser, browser *playwright.Browser,
log *slog.Logger) (err error) { log *slog.Logger) (err error) {
t := true t := true
@ -123,13 +130,13 @@ func ExecParser(
ctx, cancel := context.WithTimeout(ctx, 6*time.Minute) ctx, cancel := context.WithTimeout(ctx, 6*time.Minute)
defer page.Close() defer page.Close()
defer cancel() defer cancel()
insts, err := Scrape(ctx, page, log) insts, err := sct.Scrape(ctx, page, log)
// here we execute db operations // here we execute db operations
if err != nil { if err != nil {
return err return err
} }
for _, inst := range insts { for _, inst := range insts {
err = db.Inspect(*inst) sct.client.NewHistory(inst)
} }
return err return err
} }

View File

@ -1,4 +1,4 @@
package vimenca package crawler
import ( import (
"context" "context"
@ -6,16 +6,24 @@ import (
"os" "os"
"time" "time"
"github.com/maximotejeda/us_dop_db/db"
"github.com/maximotejeda/us_dop_scrapper/helpers" "github.com/maximotejeda/us_dop_scrapper/helpers"
"github.com/maximotejeda/us_dop_scrapper/internal/application/core/domain"
"github.com/maximotejeda/us_dop_scrapper/internal/ports"
"github.com/playwright-community/playwright-go" "github.com/playwright-community/playwright-go"
) )
var ( type vimenca struct {
uri = os.Getenv("VIMENCA") client ports.DollarPort
) }
func Scrape(ctx context.Context, page playwright.Page, log *slog.Logger) (inst *db.History, err error) { func NewVimenca(client ports.DollarPort) ports.APIPorts {
return &vimenca{
client: client,
}
}
func (v vimenca) Scrape(ctx context.Context, page playwright.Page, log *slog.Logger) (insts []*domain.History, err error) {
uri := os.Getenv("VIMENCA")
tout := 120000.00 tout := 120000.00
log = log.With("scrapper", "vimenca") log = log.With("scrapper", "vimenca")
if _, err := page.Goto(uri, playwright.PageGotoOptions{ if _, err := page.Goto(uri, playwright.PageGotoOptions{
@ -45,21 +53,20 @@ func Scrape(ctx context.Context, page playwright.Page, log *slog.Logger) (inst *
log.Error("could not get venta string", "err", err) log.Error("could not get venta string", "err", err)
return nil, err return nil, err
} }
inst = &db.History{ inst := &domain.History{
Name: "banco vimenca", Name: "banco vimenca",
Parser: "vimenca", Parser: "vimenca",
Parsed: time.Now().UTC(), Parsed: time.Now().Unix(),
} }
inst.Venta = helpers.Normalize(ventaSTR) inst.Venta = helpers.Normalize(ventaSTR)
inst.Compra = helpers.Normalize(compraSTR) inst.Compra = helpers.Normalize(compraSTR)
log.Info("institution", "value", inst) log.Info("institution", "value", inst)
return inst, nil return []*domain.History{inst}, nil
} }
func ExecParser( func (v vimenca) ExecParser(
ctx context.Context, ctx context.Context,
db *db.DB,
browser *playwright.Browser, browser *playwright.Browser,
log *slog.Logger) (err error) { log *slog.Logger) (err error) {
t := true t := true
@ -85,13 +92,15 @@ func ExecParser(
ctx, cancel := context.WithTimeout(ctx, 6*time.Minute) ctx, cancel := context.WithTimeout(ctx, 6*time.Minute)
defer page.Close() defer page.Close()
defer cancel() defer cancel()
inst, err := Scrape(ctx, page, log) inst, err := v.Scrape(ctx, page, log)
// here we execute db operations // here we execute db operations
if err != nil { if err != nil {
return err return err
} }
err = v.client.NewHistory(inst[0])
err = db.Inspect(*inst) if err != nil {
return err
}
return err return err
} }

View File

@ -1 +0,0 @@
maximo@debian-pc.9800:1713363571

View File

@ -6,21 +6,27 @@ import (
"github.com/maximotejeda/msvc-proto/golang/dolar" "github.com/maximotejeda/msvc-proto/golang/dolar"
"github.com/maximotejeda/us_dop_scrapper/internal/application/core/domain" "github.com/maximotejeda/us_dop_scrapper/internal/application/core/domain"
"google.golang.org/grpc" "google.golang.org/grpc"
"google.golang.org/grpc/credentials/insecure"
) )
type Adapter struct { type Adapter struct {
dolar dolar.DollarClient dolar dolar.DollarClient
conn *grpc.ClientConn
} }
func NewAdapter(dolarServiceURL string) (*Adapter, error) { func NewAdapter(conn *grpc.ClientConn) (*Adapter, error) {
var opts []grpc.DialOption
opts = append(opts, grpc.WithTransportCredentials(insecure.NewCredentials()))
conn, err := grpc.Dial(dolarServiceURL, opts...)
if err != nil {
return nil, err
}
defer conn.Close()
client := dolar.NewDollarClient(conn) client := dolar.NewDollarClient(conn)
return &Adapter{dolar: client}, nil return &Adapter{dolar: client, conn: conn}, nil
}
func (a *Adapter) NewHistory(history *domain.History) error {
_, err := a.dolar.NewHistory(context.Background(),
&dolar.AddDolarRequest{
Institution: &dolar.History{
Name: history.Name,
Compra: float32(history.Compra),
Venta: float32(history.Venta),
Parser: history.Parser,
Parsed: history.Parsed,
}})
return err
} }

View File

@ -1 +0,0 @@
maximo@debian-pc.9800:1713363571

View File

@ -1,10 +1,10 @@
package api package api
import ( import (
"log/slog" "context"
"github.com/maximotejeda/us_dop_scrapper/helpers"
"github.com/maximotejeda/us_dop_scrapper/config"
"github.com/maximotejeda/us_dop_scrapper/internal/ports" "github.com/maximotejeda/us_dop_scrapper/internal/ports"
"log/slog"
) )
type Application struct { type Application struct {
@ -12,15 +12,28 @@ type Application struct {
api ports.APIPorts api ports.APIPorts
} }
func NewApplication() *Application { func NewApplication(crawler ports.APIPorts) *Application {
log := slog.Default() log := slog.Default()
log = log.With("application", "root") log = log.With("application", "root")
return &Application{ return &Application{
log: log, log: log,
api: crawler,
} }
} }
func (a Application) Run() { func (a Application) Run() {
who := config.GetWho() ctx := context.Background()
ch, ff, wk := helpers.CreateBrowser(a.log)
err := a.api.ExecParser(ctx, ch, a.log)
if err != nil {
a.log.Info("failed on frist browser", "browser", "chrome", "error", err)
err := a.api.ExecParser(ctx, ff, a.log)
if err != nil {
a.log.Error("failed on second browser", "browser", "firefox", "error", err)
err := a.api.ExecParser(ctx, wk, a.log)
if err != nil {
a.log.Error("tried all browsers error", "brwser", "webkit", "error", err)
}
}
}
} }

View File

@ -1 +0,0 @@
maximo@debian-pc.9800:1713363571

View File

@ -1,10 +1,10 @@
package domain package domain
type History struct { type History struct {
ID int64 `json:""` ID int64 `json:"id"`
Name string `json:""` Name string `json:"name"`
Compra float64 `json:""` Compra float64 `json:"compra"`
Venta float64 `json:""` Venta float64 `json:"venta"`
Parser string `json:""` Parser string `json:"parser"`
Parsed int64 `json:""` Parsed int64 `json:"parsed"`
} }

View File

@ -1,51 +0,0 @@
package wait
import (
"fmt"
"time"
)
// from monday to friday from 12:00 utc to 22:00 utc
// saturday from 12:00 utc to 18:00 utc
// sunday wont work
func WaitAmount(actualTime time.Time) (infoDuration time.Duration, longDuration time.Duration) {
var nextDayTime time.Time
// day of the week start on sunday=0
dayNumber := actualTime.UTC().Weekday()
year, month, day, hour := actualTime.UTC().Year(), actualTime.UTC().Month(), actualTime.UTC().Day(), actualTime.UTC().Hour()
nextDayTemplate := fmt.Sprintf("%d-%02d-%02d 12:05:00", year, month, day)
parsedDate, err := time.Parse(time.DateTime, nextDayTemplate)
if err != nil {
panic(err)
}
// in case of waiting to next day or weekend
switch dayNumber {
case 0:
nextDayTime = parsedDate.Add(24 * time.Hour)
return time.Until(nextDayTime), time.Until(nextDayTime)
case 6:
if hour > 16 {
nextDayTime = parsedDate.Add(48 * time.Hour)
return time.Until(nextDayTime), time.Until(nextDayTime)
} else {
info := time.Until(actualTime.UTC().Add(26 * time.Minute))
long := time.Until(actualTime.UTC().Add(59 * time.Minute))
return info, long
}
default:
nextDayTime = parsedDate.Add(24 * time.Hour)
switch {
case hour >= 22:
// next day wait
return time.Until(nextDayTime), time.Until(nextDayTime)
case hour < 12:
return time.Until(parsedDate), time.Until(parsedDate)
default:
info := time.Until(actualTime.UTC().Add(26 * time.Minute))
long := time.Until(actualTime.UTC().Add(59 * time.Minute))
return info, long
}
}
}

View File

@ -1,40 +0,0 @@
package wait
import (
"testing"
"time"
)
func TestWaitAmount(t *testing.T) {
type cases struct {
name string
initDate time.Time
infoAmount float64
longAmount float64
}
scenario := []cases{
{
name: "success/3h",
initDate: time.Now().Add(-1 * time.Hour),
infoAmount: 24,
longAmount: 24,
},
{
name: "success/now",
initDate: time.Now(),
infoAmount: 24,
longAmount: 24,
},
}
for _, tt := range scenario {
t.Run(tt.name, func(t *testing.T) {
info, long := WaitAmount(tt.initDate)
if info.Hours() == 0 {
t.Errorf("wanted: %f got: %f, time: %v", tt.infoAmount, info.Hours(), tt.initDate.UTC())
}
if long.Hours() == 0 {
t.Errorf("wanted: %f got: %f, time: %v", tt.longAmount, long.Hours(), tt.initDate.UTC())
}
})
}
}