Skip to content

Instantly share code, notes, and snippets.

@shal
Last active June 9, 2019 10:08
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save shal/7bc47dee79ad3b386d553b0c47582a45 to your computer and use it in GitHub Desktop.
Save shal/7bc47dee79ad3b386d553b0c47582a45 to your computer and use it in GitHub Desktop.
[CLOSED] VIN codes extractor from hotline server
package main
// Author: Ali Shanaakh <hi@shal.dev>
import (
"encoding/json"
"errors"
"log"
"net/http"
"net/url"
"time"
"github.com/go-pg/pg"
)
const (
NumberOfWorkers = 10
Buffer = 100
)
var (
baseURL = "https://hotline.finance/api/insurance/osago/carDataByNumber/"
)
// Payload is representation of API response.
type Payload struct {
//Type string `json:"carType"`
Vin string `json:"vin"`
//Brand string `json:"markName"`
//Model string `json:"modelName"`
}
// PlatesToVIN returns VIN code by car plates.
func PlatesToVIN(number string) (string, error) {
payload := new(Payload)
encoded := url.QueryEscape(number)
resp, err := http.Get(baseURL + encoded)
if err != nil {
return "", err
}
if err := json.NewDecoder(resp.Body).Decode(payload); err != nil {
return "", err
}
return payload.Vin, nil
}
// Operation represents public registrations of transport.
type Operation struct {
Number string `db:"number,notnull"`
VIN string `db:"number"`
}
func Worker(numbers <-chan string, vins chan Operation, errs chan error) {
for {
number, open := <-numbers
// On channel close.
if !open {
return
}
vin, err := PlatesToVIN(number)
if err != nil {
errs <- err
}
vins <- Operation{
Number: number,
VIN: vin,
}
}
}
func SQLBatcher(vins <-chan Operation, errs chan error) {
db := pg.Connect(&pg.Options{
User: "postgres",
Password: "postgres",
Database: "opencars",
})
for {
op, open := <-vins
// On channel close.
if !open {
db.Close()
errs <- errors.New("closed")
return
}
log.Println(op.Number, "-", op.VIN)
_, err := db.Model((*Operation)(nil)).
Set("vin_code = ?", op.VIN).
Where("number = ?", op.Number).
Update()
if err != nil {
errs <- err
return
}
}
}
func Feeder(numbers chan string, errs chan error) {
db := pg.Connect(&pg.Options{
User: "postgres",
Password: "postgres",
Database: "opencars",
})
offset := 0
size := 100
for {
var rows []string
err := db.Model((*Operation)(nil)).
Column("number").
Where("number LIKE 'А%'").
Where("vin_code != ''").
Group("number", "date").
Order("date ASC").
Limit(size).
Offset(offset).
Select(&rows)
if err != nil {
errs <- err
return
}
for _, row := range rows {
numbers <- row
}
offset += size
}
}
func main() {
numbers := make(chan string, Buffer)
vins := make(chan Operation, Buffer)
errs := make(chan error)
go Feeder(numbers, errs)
for i := 0; i < NumberOfWorkers; i++ {
go Worker(numbers, vins, errs)
}
for i := 0; i < NumberOfWorkers; i++ {
go SQLBatcher(vins, errs)
}
for {
<-errs
time.Sleep(10)
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment