first commit
This commit is contained in:
commit
9654c6c3f3
5
go.mod
Normal file
5
go.mod
Normal file
|
@ -0,0 +1,5 @@
|
||||||
|
module git.wow.st/gmp/goget
|
||||||
|
|
||||||
|
go 1.23.0
|
||||||
|
|
||||||
|
require git.wow.st/gmp/ohlc v0.0.0-20241115023606-83f41a06596c // indirect
|
2
go.sum
Normal file
2
go.sum
Normal file
|
@ -0,0 +1,2 @@
|
||||||
|
git.wow.st/gmp/ohlc v0.0.0-20241115023606-83f41a06596c h1:etBdVfh2E4k00IzRBMuHsGm5HZg7S96JBZQpCGWshNE=
|
||||||
|
git.wow.st/gmp/ohlc v0.0.0-20241115023606-83f41a06596c/go.mod h1:QSSqMCu9AFoYtfqA9Hbfpxy3mp5MT/d4fk0AzYnuoo8=
|
154
main.go
Normal file
154
main.go
Normal file
|
@ -0,0 +1,154 @@
|
||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"git.wow.st/gmp/ohlc"
|
||||||
|
"fmt"
|
||||||
|
"io"
|
||||||
|
"net/http"
|
||||||
|
"os"
|
||||||
|
"sync"
|
||||||
|
"time"
|
||||||
|
)
|
||||||
|
|
||||||
|
var (
|
||||||
|
retries = 5
|
||||||
|
concurrency = 30
|
||||||
|
ch chan string
|
||||||
|
clk chan bool
|
||||||
|
wg sync.WaitGroup
|
||||||
|
|
||||||
|
freq = time.Second / 30
|
||||||
|
throttle bool
|
||||||
|
errs map[string]int
|
||||||
|
mu sync.Mutex
|
||||||
|
)
|
||||||
|
|
||||||
|
func get_(symbol string) (error) {
|
||||||
|
url := fmt.Sprintf("https://query2.finance.yahoo.com/v8/finance/chart/%s?period1=1&period2=3122064000&interval=1d&includeAdjustedClose=true&events=div,splits,capitalGains", symbol)
|
||||||
|
req, err := http.NewRequest(http.MethodGet, url, nil)
|
||||||
|
if err != nil {
|
||||||
|
fmt.Println("Request error (%s): ", symbol, err)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
req.Header.Set("User-Agent", "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/122.0.0.0 Safari/537.36")
|
||||||
|
resp, err := http.DefaultClient.Do(req)
|
||||||
|
if err != nil {
|
||||||
|
fmt.Println("Get error (%s): ", symbol, err)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
switch resp.StatusCode {
|
||||||
|
case 401, 429:
|
||||||
|
throttle = true
|
||||||
|
return fmt.Errorf("%s", resp.Status)
|
||||||
|
err_(symbol,0) // do not limit retries
|
||||||
|
return fmt.Errorf("%s", resp.Status)
|
||||||
|
case 404:
|
||||||
|
err_(symbol,5) // do not retry
|
||||||
|
return fmt.Errorf("%s", resp.Status)
|
||||||
|
case 200:
|
||||||
|
default:
|
||||||
|
err_(symbol,1)
|
||||||
|
return fmt.Errorf("%s", resp.Status)
|
||||||
|
}
|
||||||
|
|
||||||
|
filename := fmt.Sprintf("%s.json", symbol)
|
||||||
|
out, err := os.Create(filename)
|
||||||
|
if err != nil {
|
||||||
|
fmt.Println("Error opening output file.")
|
||||||
|
os.Exit(-1)
|
||||||
|
}
|
||||||
|
defer out.Close()
|
||||||
|
_, err = io.Copy(out, resp.Body)
|
||||||
|
resp.Body.Close()
|
||||||
|
if err != nil {
|
||||||
|
fmt.Println("Error copying to file.")
|
||||||
|
os.Exit(-1)
|
||||||
|
}
|
||||||
|
out.WriteString("\n")
|
||||||
|
out.Close()
|
||||||
|
|
||||||
|
ohlc.Conv(symbol)
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func err_(symbol string, x int) {
|
||||||
|
mu.Lock()
|
||||||
|
defer mu.Unlock()
|
||||||
|
errs[symbol] = errs[symbol]+x
|
||||||
|
str := fmt.Sprintf("Error fetching %s. Retries: %d", symbol, errs[symbol])
|
||||||
|
if errs[symbol] < retries {
|
||||||
|
go func() {
|
||||||
|
wg.Add(1)
|
||||||
|
ch <- symbol
|
||||||
|
}()
|
||||||
|
} else {
|
||||||
|
str = fmt.Sprintf("%s: aborting", str)
|
||||||
|
}
|
||||||
|
fmt.Println(str)
|
||||||
|
}
|
||||||
|
|
||||||
|
func get() {
|
||||||
|
<-clk
|
||||||
|
symbol := <-ch
|
||||||
|
defer wg.Done()
|
||||||
|
fmt.Println("Symbol = ", symbol)
|
||||||
|
|
||||||
|
err := get_(symbol)
|
||||||
|
if err != nil {
|
||||||
|
fmt.Printf("Get error (%s): %s\n", symbol, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func clock() {
|
||||||
|
for {
|
||||||
|
if (throttle) {
|
||||||
|
time.Sleep(20 * time.Second)
|
||||||
|
throttle = false
|
||||||
|
} else {
|
||||||
|
clk <- true
|
||||||
|
}
|
||||||
|
time.Sleep(freq)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
fmt.Println("goget\n")
|
||||||
|
ch = make(chan string)
|
||||||
|
clk = make(chan bool)
|
||||||
|
errs = make(map[string]int)
|
||||||
|
|
||||||
|
if len(os.Args) < 2 {
|
||||||
|
fmt.Println("Usage: goget symbol1 [symbol2...]")
|
||||||
|
os.Exit(-1)
|
||||||
|
}
|
||||||
|
|
||||||
|
go clock()
|
||||||
|
for i := 0; i < concurrency; i++ {
|
||||||
|
go func() {
|
||||||
|
for {
|
||||||
|
get()
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, x := range(os.Args[1:]) {
|
||||||
|
wg.Add(1)
|
||||||
|
ch <- x
|
||||||
|
}
|
||||||
|
|
||||||
|
wg.Wait()
|
||||||
|
|
||||||
|
var inc []string
|
||||||
|
|
||||||
|
for k,v := range errs {
|
||||||
|
if v >= 5 {
|
||||||
|
inc = append(inc, k)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if len(inc) > 0 {
|
||||||
|
fmt.Println("Failed downloads: ", inc)
|
||||||
|
}
|
||||||
|
os.Exit(0)
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user