added serve-http option
This commit is contained in:
parent
c0539ade72
commit
4a726291a2
9 changed files with 313 additions and 96 deletions
16
Readme.md
16
Readme.md
|
@ -1,13 +1,13 @@
|
||||||
The aim of my-bloody-hetzner-sb-notifier is a simple CLI to fetch the current Hetzner Serverbörse deals and filter them according to CLI parameters sorted by score.
|
The aim of my-bloody-hetzner-sb-notifier is a simple CLI to fetch the current Hetzner Serverbörse deals and filter them according to CLI parameters sorted by score.
|
||||||
|
|
||||||
The score is calculated from the amount of HDD space as well as RAM and CPU-Benchnmark for better comparability.
|
For each offer a score is calculated from the amount of HDD space as well as RAM and CPU-Benchnmark for better comparability.
|
||||||
|
|
||||||
The CLI interface looks like this:
|
The CLI interface looks like this:
|
||||||
````
|
````
|
||||||
Usage of hetzner-sb-notifier:
|
Usage of hetzner-sb-notifier:
|
||||||
-alert-on-score int
|
-min-cpu-benchmark int
|
||||||
set alert on score
|
set min benchmark
|
||||||
-max-benchmark int
|
-max-cpu-benchmark int
|
||||||
set max benchmark (default 20000)
|
set max benchmark (default 20000)
|
||||||
-max-hdd-count int
|
-max-hdd-count int
|
||||||
set max hdd count (default 15)
|
set max hdd count (default 15)
|
||||||
|
@ -17,8 +17,6 @@ Usage of hetzner-sb-notifier:
|
||||||
set max price (default 297)
|
set max price (default 297)
|
||||||
-max-ram int
|
-max-ram int
|
||||||
set max ram (default 256)
|
set max ram (default 256)
|
||||||
-min-benchmark int
|
|
||||||
set min benchmark
|
|
||||||
-min-hdd-count int
|
-min-hdd-count int
|
||||||
set min hdd count
|
set min hdd count
|
||||||
-min-hdd-size int
|
-min-hdd-size int
|
||||||
|
@ -27,8 +25,14 @@ Usage of hetzner-sb-notifier:
|
||||||
set min price
|
set min price
|
||||||
-min-ram int
|
-min-ram int
|
||||||
set min ram
|
set min ram
|
||||||
|
-serve-http
|
||||||
|
set serve http
|
||||||
|
-serve-http-port int
|
||||||
|
set serve http port (default 8080)
|
||||||
````
|
````
|
||||||
|
|
||||||
|
## Http mode
|
||||||
|
|
||||||
## Example
|
## Example
|
||||||
|
|
||||||
./hetzner-sb-notifier --max-price 77 --min-ram 128 --min-hdd-count 2 --min-hdd-size 4096
|
./hetzner-sb-notifier --max-price 77 --min-ram 128 --min-hdd-count 2 --min-hdd-size 4096
|
||||||
|
|
|
@ -1,51 +1,41 @@
|
||||||
package crawler
|
package crawler
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
|
||||||
"github.com/mrahbar/my-bloody-hetzner-sb-notifier/hetzner"
|
"github.com/mrahbar/my-bloody-hetzner-sb-notifier/hetzner"
|
||||||
"os"
|
|
||||||
"sort"
|
"sort"
|
||||||
"text/tabwriter"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
type Crawler struct {
|
type Parameter struct {
|
||||||
tabWriter *tabwriter.Writer
|
MinPrice float64
|
||||||
|
MaxPrice float64
|
||||||
|
|
||||||
minPrice float64
|
MinRam int64
|
||||||
maxPrice float64
|
MaxRam int64
|
||||||
|
|
||||||
minRam int
|
MinHddSize int64
|
||||||
maxRam int
|
MaxHddSize int64
|
||||||
|
|
||||||
minHddSize int
|
MinHddCount int64
|
||||||
maxHddSize int
|
MaxHddCount int64
|
||||||
|
|
||||||
minHddCount int
|
MinBenchmark int64
|
||||||
maxHddCount int
|
MaxBenchmark int64
|
||||||
|
|
||||||
minBenchmark int
|
|
||||||
maxBenchmark int
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewCrawler(minPrice float64, maxPrice float64, minRam int, maxRam int, minHddSize int, maxHddSize int, minHddCount int, maxHddCount int, minBenchmark int, maxBenchmark int) *Crawler {
|
|
||||||
|
type Crawler struct {
|
||||||
|
parameter Parameter
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewCrawler(parameter Parameter) *Crawler {
|
||||||
crawler := &Crawler{
|
crawler := &Crawler{
|
||||||
tabwriter.NewWriter(os.Stdout, 0, 8, 2, ' ', tabwriter.Debug|tabwriter.AlignRight),
|
parameter: parameter,
|
||||||
minPrice,
|
|
||||||
maxPrice,
|
|
||||||
minRam,
|
|
||||||
maxRam,
|
|
||||||
minHddSize,
|
|
||||||
maxHddSize,
|
|
||||||
minHddCount,
|
|
||||||
maxHddCount,
|
|
||||||
minBenchmark,
|
|
||||||
maxBenchmark,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return crawler
|
return crawler
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *Crawler) Filter(servers []hetzner.Server) []hetzner.Server {
|
func (c *Crawler) Filter(servers []hetzner.Server) hetzner.Deals {
|
||||||
var filteredServers []hetzner.Server
|
var filteredServers []hetzner.Server
|
||||||
for _, server := range servers {
|
for _, server := range servers {
|
||||||
if !c.isFiltered(server) {
|
if !c.isFiltered(server) {
|
||||||
|
@ -56,26 +46,23 @@ func (c *Crawler) Filter(servers []hetzner.Server) []hetzner.Server {
|
||||||
sort.Slice(servers, func(i, j int) bool {
|
sort.Slice(servers, func(i, j int) bool {
|
||||||
return servers[i].Score() > servers[j].Score()
|
return servers[i].Score() > servers[j].Score()
|
||||||
})
|
})
|
||||||
return filteredServers
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c *Crawler) Print(servers []hetzner.Server) {
|
deals := hetzner.Deals{
|
||||||
fmt.Fprintf(c.tabWriter, "%s\n", servers[0].Header())
|
ResultStats: hetzner.FilterResultStats{OriginalCount: len(servers), FilteredCount: len(filteredServers)},
|
||||||
for _, server := range servers {
|
Servers: filteredServers,
|
||||||
fmt.Fprintf(c.tabWriter, "%s\n", server.ToString())
|
|
||||||
}
|
}
|
||||||
c.tabWriter.Flush()
|
return deals
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *Crawler) isFiltered(server hetzner.Server) bool {
|
func (c *Crawler) isFiltered(server hetzner.Server) bool {
|
||||||
filtered := true
|
filtered := true
|
||||||
|
|
||||||
priceParsed := server.ParsePrice()
|
priceParsed := server.ParsePrice()
|
||||||
if server.CpuBenchmark >= c.minBenchmark && server.CpuBenchmark <= c.maxBenchmark &&
|
if server.CpuBenchmark >= c.parameter.MinBenchmark && server.CpuBenchmark <= c.parameter.MaxBenchmark &&
|
||||||
priceParsed >= c.minPrice && priceParsed <= c.maxPrice &&
|
priceParsed >= c.parameter.MinPrice && priceParsed <= c.parameter.MaxPrice &&
|
||||||
server.Ram >= c.minRam && server.Ram <= c.maxRam &&
|
server.Ram >= c.parameter.MinRam && server.Ram <= c.parameter.MaxRam &&
|
||||||
server.TotalHdd() >= c.minHddSize && server.TotalHdd() <= c.maxHddSize &&
|
server.TotalHdd() >= c.parameter.MinHddSize && server.TotalHdd() <= c.parameter.MaxHddSize &&
|
||||||
server.HddCount >= c.minHddCount && server.HddCount <= c.maxHddCount {
|
server.HddCount >= c.parameter.MinHddCount && server.HddCount <= c.parameter.MaxHddCount {
|
||||||
filtered = false
|
filtered = false
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
1
go.mod
1
go.mod
|
@ -4,6 +4,7 @@ require (
|
||||||
cloud.google.com/go v0.31.0
|
cloud.google.com/go v0.31.0
|
||||||
github.com/golang/protobuf v1.2.0
|
github.com/golang/protobuf v1.2.0
|
||||||
github.com/googleapis/gax-go v2.0.0+incompatible // indirect
|
github.com/googleapis/gax-go v2.0.0+incompatible // indirect
|
||||||
|
github.com/iancoleman/strcase v0.0.0-20180726023541-3605ed457bf7 // indirect
|
||||||
github.com/mitchellh/gox v0.4.0 // indirect
|
github.com/mitchellh/gox v0.4.0 // indirect
|
||||||
github.com/mitchellh/iochan v1.0.0 // indirect
|
github.com/mitchellh/iochan v1.0.0 // indirect
|
||||||
go.opencensus.io v0.18.0 // indirect
|
go.opencensus.io v0.18.0 // indirect
|
||||||
|
|
|
@ -6,6 +6,16 @@ import (
|
||||||
"strings"
|
"strings"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
type Deals struct {
|
||||||
|
ResultStats FilterResultStats
|
||||||
|
Servers []Server
|
||||||
|
}
|
||||||
|
|
||||||
|
type FilterResultStats struct {
|
||||||
|
OriginalCount int `json:"count"`
|
||||||
|
FilteredCount int `json:"filtered"`
|
||||||
|
}
|
||||||
|
|
||||||
type Offers struct {
|
type Offers struct {
|
||||||
Server []Server `json:"server"`
|
Server []Server `json:"server"`
|
||||||
}
|
}
|
||||||
|
@ -26,13 +36,13 @@ type Server struct {
|
||||||
SetupPrice string `json:"setup_price"`
|
SetupPrice string `json:"setup_price"`
|
||||||
|
|
||||||
Cpu string `json:"cpu"`
|
Cpu string `json:"cpu"`
|
||||||
CpuBenchmark int `json:"cpu_benchmark"`
|
CpuBenchmark int64 `json:"cpu_benchmark"`
|
||||||
CpuCount int `json:"cpu_count"`
|
CpuCount int64 `json:"cpu_count"`
|
||||||
Ram int `json:"ram"`
|
Ram int64 `json:"ram"`
|
||||||
RamHr string `json:"ram_hr"`
|
RamHr string `json:"ram_hr"`
|
||||||
HddSize int `json:"hdd_size"`
|
HddSize int64 `json:"hdd_size"`
|
||||||
HddHr string `json:"hdd_hr"`
|
HddHr string `json:"hdd_hr"`
|
||||||
HddCount int `json:"hdd_count"`
|
HddCount int64 `json:"hdd_count"`
|
||||||
SpecialHdd string `json:"specialHdd"`
|
SpecialHdd string `json:"specialHdd"`
|
||||||
|
|
||||||
NextReduce int `json:"next_reduce"`
|
NextReduce int `json:"next_reduce"`
|
||||||
|
@ -43,7 +53,7 @@ type Server struct {
|
||||||
IsEcc bool `json:"is_ecc"`
|
IsEcc bool `json:"is_ecc"`
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *Server) TotalHdd() int {
|
func (s *Server) TotalHdd() int64 {
|
||||||
return s.HddCount * s.HddSize
|
return s.HddCount * s.HddSize
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,11 +0,0 @@
|
||||||
package instrumentation
|
|
||||||
|
|
||||||
type Instrumenter struct {
|
|
||||||
projectID string
|
|
||||||
}
|
|
||||||
|
|
||||||
func NewInstrumenter(projectID string) *Instrumenter {
|
|
||||||
return &Instrumenter{
|
|
||||||
projectID: projectID,
|
|
||||||
}
|
|
||||||
}
|
|
228
main.go
228
main.go
|
@ -3,92 +3,256 @@ package main
|
||||||
import (
|
import (
|
||||||
"flag"
|
"flag"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"github.com/iancoleman/strcase"
|
||||||
"github.com/mrahbar/my-bloody-hetzner-sb-notifier/client"
|
"github.com/mrahbar/my-bloody-hetzner-sb-notifier/client"
|
||||||
c "github.com/mrahbar/my-bloody-hetzner-sb-notifier/crawler"
|
"github.com/mrahbar/my-bloody-hetzner-sb-notifier/crawler"
|
||||||
"github.com/mrahbar/my-bloody-hetzner-sb-notifier/hetzner"
|
"github.com/mrahbar/my-bloody-hetzner-sb-notifier/hetzner"
|
||||||
|
"github.com/mrahbar/my-bloody-hetzner-sb-notifier/writer"
|
||||||
|
"io"
|
||||||
|
"net/http"
|
||||||
|
"net/http/httputil"
|
||||||
|
"os"
|
||||||
|
"strconv"
|
||||||
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
flagMinPrice = "min-price"
|
||||||
|
flagMaxPrice = "max-price"
|
||||||
|
flagMinRam = "min-ram"
|
||||||
|
flagMaxRam = "max-ram"
|
||||||
|
flagMinHddSize = "min-hdd-size"
|
||||||
|
flagMaxHddSize = "max-hdd-size"
|
||||||
|
flagMinHddCount = "min-hdd-count"
|
||||||
|
flagMaxHddCount = "max-hdd-count"
|
||||||
|
flagMinBenchmark = "min-cpu-benchmark"
|
||||||
|
flagMaxBenchmark = "max-cpu-benchmark"
|
||||||
|
|
||||||
|
flagOutput = "output"
|
||||||
|
flagServeHttpPort = "serve-http-port"
|
||||||
|
flagServeHttp = "serve-http"
|
||||||
)
|
)
|
||||||
|
|
||||||
var (
|
var (
|
||||||
|
zeroIntValue = int64(0)
|
||||||
|
zeroFloatValue = float64(0)
|
||||||
|
|
||||||
|
defaultMaxPriceValue = float64(297)
|
||||||
|
defaultMaxRamValue = int64(256)
|
||||||
|
defaultMaxHddSizeValue = int64(6144)
|
||||||
|
defaultMaxHddCountValue = int64(15)
|
||||||
|
defaultMaxCpuBenchmarkValue = int64(20000)
|
||||||
|
|
||||||
minPrice = flag.Float64(
|
minPrice = flag.Float64(
|
||||||
"min-price",
|
flagMinPrice,
|
||||||
0,
|
0,
|
||||||
"set min price",
|
"set min price",
|
||||||
)
|
)
|
||||||
maxPrice = flag.Float64(
|
maxPrice = flag.Float64(
|
||||||
"max-price",
|
flagMaxPrice,
|
||||||
297,
|
297,
|
||||||
"set max price",
|
"set max price",
|
||||||
)
|
)
|
||||||
|
|
||||||
minRam = flag.Int(
|
minRam = flag.Int64(
|
||||||
"min-ram",
|
flagMinRam,
|
||||||
0,
|
0,
|
||||||
"set min ram",
|
"set min ram",
|
||||||
)
|
)
|
||||||
maxRam = flag.Int(
|
maxRam = flag.Int64(
|
||||||
"max-ram",
|
flagMaxRam,
|
||||||
256,
|
256,
|
||||||
"set max ram",
|
"set max ram",
|
||||||
)
|
)
|
||||||
|
|
||||||
minHddSize = flag.Int(
|
minHddSize = flag.Int64(
|
||||||
"min-hdd-size",
|
flagMinHddSize,
|
||||||
0,
|
0,
|
||||||
"set min hdd size",
|
"set min hdd size",
|
||||||
)
|
)
|
||||||
maxHddSize = flag.Int(
|
maxHddSize = flag.Int64(
|
||||||
"max-hdd-size",
|
flagMaxHddSize,
|
||||||
6144,
|
6144,
|
||||||
"set max hdd size",
|
"set max hdd size",
|
||||||
)
|
)
|
||||||
|
|
||||||
minHddCount = flag.Int(
|
minHddCount = flag.Int64(
|
||||||
"min-hdd-count",
|
flagMinHddCount,
|
||||||
0,
|
0,
|
||||||
"set min hdd count",
|
"set min hdd count",
|
||||||
)
|
)
|
||||||
maxHddCount = flag.Int(
|
maxHddCount = flag.Int64(
|
||||||
"max-hdd-count",
|
flagMaxHddCount,
|
||||||
15,
|
15,
|
||||||
"set max hdd count",
|
"set max hdd count",
|
||||||
)
|
)
|
||||||
|
|
||||||
minBenchmark = flag.Int(
|
minBenchmark = flag.Int64(
|
||||||
"min-benchmark",
|
flagMinBenchmark,
|
||||||
0,
|
0,
|
||||||
"set min benchmark",
|
"set min benchmark",
|
||||||
)
|
)
|
||||||
maxBenchmark = flag.Int(
|
maxBenchmark = flag.Int64(
|
||||||
"max-benchmark",
|
flagMaxBenchmark,
|
||||||
20000,
|
20000,
|
||||||
"set max benchmark",
|
"set max benchmark",
|
||||||
)
|
)
|
||||||
|
|
||||||
alertOnScore = flag.Int(
|
serveHttp = flag.Bool(
|
||||||
"alert-on-score",
|
flagServeHttp,
|
||||||
0,
|
false,
|
||||||
"set alert on score",
|
"set serve http",
|
||||||
|
)
|
||||||
|
|
||||||
|
serveHttpPort = flag.Int(
|
||||||
|
flagServeHttpPort,
|
||||||
|
8080,
|
||||||
|
"set serve http port",
|
||||||
|
)
|
||||||
|
|
||||||
|
output = flag.String(
|
||||||
|
flagOutput,
|
||||||
|
"table",
|
||||||
|
"set output: one of table, json",
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
flag.Parse()
|
flag.Parse()
|
||||||
|
|
||||||
|
if *serveHttp {
|
||||||
|
runHttp()
|
||||||
|
} else {
|
||||||
|
p := crawler.Parameter{
|
||||||
|
MinPrice: *minPrice,
|
||||||
|
MaxPrice: *maxPrice,
|
||||||
|
MinRam: *minRam,
|
||||||
|
MaxRam: *maxRam,
|
||||||
|
MinHddSize: *minHddSize,
|
||||||
|
MaxHddSize: *maxHddSize,
|
||||||
|
MinHddCount: *minHddCount,
|
||||||
|
MaxHddCount: *maxHddCount,
|
||||||
|
MinBenchmark: *minBenchmark,
|
||||||
|
MaxBenchmark: *maxBenchmark,
|
||||||
|
}
|
||||||
|
|
||||||
|
run(os.Stdout, p, *output)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func runHttp() {
|
||||||
|
http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
|
||||||
|
b, err := httputil.DumpRequest(r, false)
|
||||||
|
if err == nil {
|
||||||
|
fmt.Printf("Got request: %s", string(b))
|
||||||
|
}
|
||||||
|
parameter := crawler.Parameter{
|
||||||
|
MinPrice: zeroFloatValue,
|
||||||
|
MaxPrice: defaultMaxPriceValue,
|
||||||
|
MinRam: zeroIntValue,
|
||||||
|
MaxRam: defaultMaxRamValue,
|
||||||
|
MinHddSize: zeroIntValue,
|
||||||
|
MaxHddSize: defaultMaxHddSizeValue,
|
||||||
|
MinHddCount: zeroIntValue,
|
||||||
|
MaxHddCount: defaultMaxHddCountValue,
|
||||||
|
MinBenchmark: zeroIntValue,
|
||||||
|
MaxBenchmark: defaultMaxCpuBenchmarkValue,
|
||||||
|
}
|
||||||
|
output := "table"
|
||||||
|
values := r.URL.Query()
|
||||||
|
for k, v := range values {
|
||||||
|
value := v[0]
|
||||||
|
|
||||||
|
switch k {
|
||||||
|
case strcase.ToLowerCamel(flagMinPrice):
|
||||||
|
parameter.MinPrice = parseFloatFlag(w, strcase.ToLowerCamel(flagMinPrice), value)
|
||||||
|
break
|
||||||
|
case strcase.ToLowerCamel(flagMaxPrice):
|
||||||
|
parameter.MaxPrice = parseFloatFlag(w, strcase.ToLowerCamel(flagMaxPrice), value)
|
||||||
|
break
|
||||||
|
case strcase.ToLowerCamel(flagMinRam):
|
||||||
|
parameter.MinRam = parseIntFlag(w, strcase.ToLowerCamel(flagMinRam), value)
|
||||||
|
break
|
||||||
|
case strcase.ToLowerCamel(flagMaxRam):
|
||||||
|
parameter.MaxRam = parseIntFlag(w, strcase.ToLowerCamel(flagMaxRam), value)
|
||||||
|
break
|
||||||
|
case strcase.ToLowerCamel(flagMinHddSize):
|
||||||
|
parameter.MinHddSize = parseIntFlag(w, strcase.ToLowerCamel(flagMinHddSize), value)
|
||||||
|
break
|
||||||
|
case strcase.ToLowerCamel(flagMaxHddSize):
|
||||||
|
parameter.MaxHddSize = parseIntFlag(w, strcase.ToLowerCamel(flagMaxHddSize), value)
|
||||||
|
break
|
||||||
|
case strcase.ToLowerCamel(flagMinHddCount):
|
||||||
|
parameter.MinHddCount = parseIntFlag(w, strcase.ToLowerCamel(flagMinHddCount), value)
|
||||||
|
break
|
||||||
|
case strcase.ToLowerCamel(flagMaxHddCount):
|
||||||
|
parameter.MaxHddCount = parseIntFlag(w, strcase.ToLowerCamel(flagMaxHddCount), value)
|
||||||
|
break
|
||||||
|
case strcase.ToLowerCamel(flagMinBenchmark):
|
||||||
|
parameter.MinBenchmark = parseIntFlag(w, strcase.ToLowerCamel(flagMinBenchmark), value)
|
||||||
|
break
|
||||||
|
case strcase.ToLowerCamel(flagMaxBenchmark):
|
||||||
|
parameter.MaxBenchmark = parseIntFlag(w, strcase.ToLowerCamel(flagMaxBenchmark), value)
|
||||||
|
break
|
||||||
|
case strcase.ToLowerCamel(flagOutput):
|
||||||
|
output = value
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
w.WriteHeader(http.StatusOK)
|
||||||
|
run(w, parameter, output)
|
||||||
|
})
|
||||||
|
address := fmt.Sprintf(":%d", *serveHttpPort)
|
||||||
|
fmt.Printf("Running http server on address %s\n", address)
|
||||||
|
fmt.Println(http.ListenAndServe(address, nil))
|
||||||
|
}
|
||||||
|
|
||||||
|
func parseFloatFlag(w http.ResponseWriter, flag string, value string) float64 {
|
||||||
|
parseValue, err := strconv.ParseFloat(value, 32)
|
||||||
|
if err == nil {
|
||||||
|
return parseValue
|
||||||
|
} else {
|
||||||
|
writeBadRequestResponseForQueryParameter(w, flag, err)
|
||||||
|
return zeroFloatValue
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func parseIntFlag(w http.ResponseWriter, flag string, value string) int64 {
|
||||||
|
parseValue, err := strconv.ParseInt(value, 10, 32)
|
||||||
|
if err == nil {
|
||||||
|
return parseValue
|
||||||
|
} else {
|
||||||
|
writeBadRequestResponseForQueryParameter(w, flag, err)
|
||||||
|
return zeroIntValue
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func writeBadRequestResponseForQueryParameter(w http.ResponseWriter, parameter string, err error) {
|
||||||
|
w.WriteHeader(http.StatusBadRequest)
|
||||||
|
w.Write([]byte(fmt.Sprintf("Error parsing query parameter %s: %s", parameter, err)))
|
||||||
|
}
|
||||||
|
|
||||||
|
func run(w io.Writer, parameter crawler.Parameter, output string) error {
|
||||||
offers := &hetzner.Offers{}
|
offers := &hetzner.Offers{}
|
||||||
err := client.NewClient().DoRequest(hetzner.MakeURL(), offers)
|
err := client.NewClient().DoRequest(hetzner.MakeURL(), offers)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
panic(fmt.Errorf("failed to get hetzner live data: %s", err))
|
return fmt.Errorf("failed to get hetzner live data: %s", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
if len(offers.Server) > 0 {
|
if len(offers.Server) > 0 {
|
||||||
crawler := c.NewCrawler(*minPrice, *maxPrice, *minRam, *maxRam, *minHddSize, *maxHddSize, *minHddCount, *maxHddCount, *minBenchmark, *maxBenchmark)
|
c := crawler.NewCrawler(parameter)
|
||||||
servers := crawler.Filter(offers.Server)
|
deals := c.Filter(offers.Server)
|
||||||
|
|
||||||
fmt.Printf("Got %d offers. Filtered offers: %d\n", len(offers.Server), len(servers))
|
switch output {
|
||||||
crawler.Print(servers)
|
case "json":
|
||||||
|
writer.NewJsonWriter(w).Print(deals)
|
||||||
//notifier := n.NewInstrumenter(*notifierRecipient, *notifierSender, *notifierPassword)
|
break
|
||||||
|
default:
|
||||||
|
case "table":
|
||||||
|
writer.NewTableWriter(w).Print(deals)
|
||||||
|
break
|
||||||
|
}
|
||||||
|
return nil
|
||||||
} else {
|
} else {
|
||||||
fmt.Println("Got no offers.")
|
return fmt.Errorf("got no offers.")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
27
writer/json.go
Normal file
27
writer/json.go
Normal file
|
@ -0,0 +1,27 @@
|
||||||
|
package writer
|
||||||
|
|
||||||
|
import (
|
||||||
|
"encoding/json"
|
||||||
|
"fmt"
|
||||||
|
"github.com/mrahbar/my-bloody-hetzner-sb-notifier/hetzner"
|
||||||
|
"io"
|
||||||
|
)
|
||||||
|
|
||||||
|
type JsonWriter struct {
|
||||||
|
output io.Writer
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewJsonWriter(output io.Writer)*JsonWriter {
|
||||||
|
return &JsonWriter{
|
||||||
|
output:output,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *JsonWriter) Print(deals hetzner.Deals) {
|
||||||
|
b, err := json.Marshal(deals)
|
||||||
|
if err != nil {
|
||||||
|
fmt.Fprintf(c.output, "{\"error\": \"%s\"}", err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
fmt.Fprint(c.output, string(b))
|
||||||
|
}
|
28
writer/table.go
Normal file
28
writer/table.go
Normal file
|
@ -0,0 +1,28 @@
|
||||||
|
package writer
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"github.com/mrahbar/my-bloody-hetzner-sb-notifier/hetzner"
|
||||||
|
"io"
|
||||||
|
"text/tabwriter"
|
||||||
|
)
|
||||||
|
|
||||||
|
type TableWriter struct {
|
||||||
|
tabWriter *tabwriter.Writer
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewTableWriter(output io.Writer)*TableWriter {
|
||||||
|
return &TableWriter{
|
||||||
|
tabwriter.NewWriter(output, 0, 8, 2, ' ', tabwriter.Debug|tabwriter.AlignRight),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *TableWriter) Print(deals hetzner.Deals) {
|
||||||
|
fmt.Fprintf(c.tabWriter,"Got %d offers. Filtered offers: %d\n", deals.ResultStats.OriginalCount, deals.ResultStats.FilteredCount)
|
||||||
|
|
||||||
|
fmt.Fprintf(c.tabWriter, "%s\n", deals.Servers[0].Header())
|
||||||
|
for _, server := range deals.Servers {
|
||||||
|
fmt.Fprintf(c.tabWriter, "%s\n", server.ToString())
|
||||||
|
}
|
||||||
|
c.tabWriter.Flush()
|
||||||
|
}
|
7
writer/writer.go
Normal file
7
writer/writer.go
Normal file
|
@ -0,0 +1,7 @@
|
||||||
|
package writer
|
||||||
|
|
||||||
|
import "github.com/mrahbar/my-bloody-hetzner-sb-notifier/hetzner"
|
||||||
|
|
||||||
|
type Writer interface {
|
||||||
|
Print(deals hetzner.Deals)
|
||||||
|
}
|
Reference in a new issue