Last active
June 9, 2019 10:08
-
-
Save shal/7bc47dee79ad3b386d553b0c47582a45 to your computer and use it in GitHub Desktop.
[CLOSED] VIN codes extractor from hotline server
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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