diff --git a/broker/broker.go b/broker/broker.go new file mode 100644 index 0000000..8657464 --- /dev/null +++ b/broker/broker.go @@ -0,0 +1,7 @@ +package broker + +import "local/truckstop/config" + +type Broker interface { + Search([]config.State) ([]Job, error) +} diff --git a/broker/job.go b/broker/job.go new file mode 100644 index 0000000..57486f5 --- /dev/null +++ b/broker/job.go @@ -0,0 +1,34 @@ +package broker + +import ( + "fmt" + "time" +) + +type Job struct { + ID string + Pickup JobLocation + Dropoff JobLocation + Weight int + Meta string +} + +type JobLocation struct { + Date time.Time + City string + State string +} + +func (j Job) String() string { + return fmt.Sprintf( + `%s => %s, Weight:%d, Notes:%s`, + j.Pickup.String(), + j.Dropoff.String(), + j.Weight, + j.Meta, + ) +} + +func (j JobLocation) String() string { + return fmt.Sprintf("%s, %s @ %s", j.City, j.State, j.Date.Format("Monday Jan 02")) +} diff --git a/broker/ntgvision.go b/broker/ntgvision.go new file mode 100644 index 0000000..687d825 --- /dev/null +++ b/broker/ntgvision.go @@ -0,0 +1,81 @@ +package broker + +import ( + "encoding/json" + "errors" + "fmt" + "io" + "local/truckstop/config" + "time" +) + +type NTGVision struct { + searcher interface { + search(states []config.State) (io.ReadCloser, error) + } +} + +type ntgVisionJob struct { + ID int64 `json:"id"` + PickupDate string `json:"sDate"` + PickupCity string `json:"sCity"` + PickupState string `json:"sState"` + DropoffDate string `json:"cDate"` + DropoffCity string `json:"cCity"` + DropoffState string `json:"cState"` + Weight int `json:"weight"` + Equipment string `json:"equip"` + Temp string `json:"temp"` +} + +func (ntgJob ntgVisionJob) Job() Job { + pickup, _ := time.ParseInLocation("01/02/06", ntgJob.PickupDate, time.Local) + dropoff, _ := time.ParseInLocation("01/02/06", ntgJob.DropoffDate, time.Local) + return Job{ + ID: fmt.Sprintf("ntg-%d", ntgJob.ID), + Pickup: JobLocation{ + Date: pickup, + City: ntgJob.PickupCity, + State: ntgJob.PickupState, + }, + Dropoff: JobLocation{ + Date: dropoff, + City: ntgJob.DropoffCity, + State: ntgJob.DropoffState, + }, + Weight: ntgJob.Weight, + Meta: fmt.Sprintf("equipment:%s", ntgJob.Equipment), + } +} + +func NewNTGVision() NTGVision { + ntgv := NTGVision{} + ntgv.searcher = ntgv + return ntgv +} + +func (ntg NTGVision) WithMock() NTGVision { + ntg.searcher = NewNTGVisionMock() + return ntg +} + +func (ntg NTGVision) search(states []config.State) (io.ReadCloser, error) { + return nil, errors.New("not impl: ntg.search") +} + +func (ntg NTGVision) Search(states []config.State) ([]Job, error) { + rc, err := ntg.searcher.search(states) + if err != nil { + return nil, err + } + defer rc.Close() + + var ntgjobs []ntgVisionJob + err = json.NewDecoder(rc).Decode(&ntgjobs) + + jobs := make([]Job, len(ntgjobs)) + for i := range jobs { + jobs[i] = ntgjobs[i].Job() + } + return jobs, err +} diff --git a/broker/ntgvision_mock.go b/broker/ntgvision_mock.go new file mode 100644 index 0000000..90cc588 --- /dev/null +++ b/broker/ntgvision_mock.go @@ -0,0 +1,22 @@ +package broker + +import ( + "bytes" + "io" + "io/ioutil" + "local/truckstop/config" + "os" + "path" +) + +type NTGVisionMock struct{} + +func NewNTGVisionMock() NTGVisionMock { + return NTGVisionMock{} +} + +func (ntgm NTGVisionMock) search(states []config.State) (io.ReadCloser, error) { + path := path.Join(os.Getenv("GOPATH"), "src", "local", "truckstop", "broker", "testdata", "ntgvision_response.json") + b, err := ioutil.ReadFile(path) + return io.NopCloser(bytes.NewReader(b)), err +} diff --git a/broker/testdata/ntgvision_response.json b/broker/testdata/ntgvision_response.json new file mode 100644 index 0000000..0f11bd0 --- /dev/null +++ b/broker/testdata/ntgvision_response.json @@ -0,0 +1,36 @@ +[ + { + "id": 4650337, + "sDate": "01/12/22", + "sCity": "Columbus", + "sState": "OH", + "sdh": null, + "cDate": "01/13/22", + "cCity": "Jamaica", + "cState": "NY", + "cdh": null, + "stopCnt": 2, + "miles": 578, + "weight": 5000, + "equip": "Str Truck W/ Lift Gate", + "temp": "", + "alertReasons": [] + }, + { + "id": 4650338, + "sDate": "01/12/22", + "sCity": "Columbus", + "sState": "OH", + "sdh": null, + "cDate": "01/13/22", + "cCity": "Jamaica", + "cState": "NY", + "cdh": null, + "stopCnt": 2, + "miles": 578, + "weight": 5000, + "equip": "Str Truck W/ Lift Gate", + "temp": "", + "alertReasons": [] + } +] diff --git a/broker/testdata/ntgvision_search.sh b/broker/testdata/ntgvision_search.sh new file mode 100644 index 0000000..f329c71 --- /dev/null +++ b/broker/testdata/ntgvision_search.sh @@ -0,0 +1,36 @@ +#! /bin/bash + +curl \ + 'https://ntgvision.com/api/v1/load/LoadBoardSearchResults' \ + -X POST \ + -H 'User-Agent: Mozilla/5.0 (Windows NT 10.0; rv:91.0) Gecko/20100101 Firefox/91.0' \ + -H 'Accept: application/json, text/plain, */*' \ + -H 'Accept-Language: en-US,en;q=0.5' \ + -H 'Accept-Encoding: gzip, deflate, br' \ + -H 'Content-Type: application/json;charset=utf-8' \ + -H 'Authorization: Bearer eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMzgyMSIsInVuaXF1ZV9uYW1lIjoiYmlyZGNvbXBhbnlsb2dpc3RpY3NAZ21haWwuY29tIiwianRpIjoiODRiNWM5ODItMjc0ZS00YmQwLTg1NjktYmFjYWQ1OWVmOTRhIiwiaWF0IjoiMS8xMC8yMDIyIDI6MjU6MjcgQU0iLCJudGd2Um9sZSI6IkNhcnJpZXJBcHByb3ZlZCIsImxvY2tVc2VyIjoiRmFsc2UiLCJvdmVycmlkZUJsYWNrbGlzdCI6IkZhbHNlIiwic2hvd1JhdGVzIjoiRmFsc2UiLCJ1c2VyQ2FycmllcnMiOiIxMTQxOTMiLCJvdHJVc2VyIjoiRmFsc2UiLCJuYmYiOjE2NDE3ODE1MjcsImV4cCI6MTY0MTg2NDMyNywiaXNzIjoiTlRHIFNlY3VyaXR5IFRva2VuIFNlcnZpY2UiLCJhdWQiOiJOVEcifQ.BfkdMsDlzjJOZJLju00mkmY8efZewV-CuYuq0el6dsiDH6UnlnuPL286QcpzKmi5642WCvneWfaFiDgj92HmiDSFTtaMYPTVI8cvX6TxQ2zs88RyNZ6FzA1ga0xLu0x6VjDrkSS1VAk7mi4xmttnsaUSnUsQ85dbEyXRG_k1M9EHRq17rcCEz8t-s3u4S9JzPRRHmHCEVe8m6R13jAJSf70MVNUiRG_7zIzfIBJJpv9cLkrp-WmtPwjuabUE9lBtfvewBmevT6ZGlfljjpBa-W6I6dO8qU-6TKV3UaBXiYZoGC_YGzT_9VHZ_TC9GnH3oB69EeIm8exwQLthOJcP3w' \ + -H 'Origin: https://ntgvision.com' \ + -H 'DNT: 1' \ + -H 'Connection: keep-alive' \ + -H 'Cookie: cookiesession1=678A3E1398901234BCDEFGHIJKLMA492; NTGAuthToken=eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMzgyMSIsInVuaXF1ZV9uYW1lIjoiYmlyZGNvbXBhbnlsb2dpc3RpY3NAZ21haWwuY29tIiwianRpIjoiODRiNWM5ODItMjc0ZS00YmQwLTg1NjktYmFjYWQ1OWVmOTRhIiwiaWF0IjoiMS8xMC8yMDIyIDI6MjU6MjcgQU0iLCJudGd2Um9sZSI6IkNhcnJpZXJBcHByb3ZlZCIsImxvY2tVc2VyIjoiRmFsc2UiLCJvdmVycmlkZUJsYWNrbGlzdCI6IkZhbHNlIiwic2hvd1JhdGVzIjoiRmFsc2UiLCJ1c2VyQ2FycmllcnMiOiIxMTQxOTMiLCJvdHJVc2VyIjoiRmFsc2UiLCJuYmYiOjE2NDE3ODE1MjcsImV4cCI6MTY0MTg2NDMyNywiaXNzIjoiTlRHIFNlY3VyaXR5IFRva2VuIFNlcnZpY2UiLCJhdWQiOiJOVEcifQ.BfkdMsDlzjJOZJLju00mkmY8efZewV-CuYuq0el6dsiDH6UnlnuPL286QcpzKmi5642WCvneWfaFiDgj92HmiDSFTtaMYPTVI8cvX6TxQ2zs88RyNZ6FzA1ga0xLu0x6VjDrkSS1VAk7mi4xmttnsaUSnUsQ85dbEyXRG_k1M9EHRq17rcCEz8t-s3u4S9JzPRRHmHCEVe8m6R13jAJSf70MVNUiRG_7zIzfIBJJpv9cLkrp-WmtPwjuabUE9lBtfvewBmevT6ZGlfljjpBa-W6I6dO8qU-6TKV3UaBXiYZoGC_YGzT_9VHZ_TC9GnH3oB69EeIm8exwQLthOJcP3w; _uiq_id.711119701.3d83=d0781b15ed3c1fb3.1641781528.0.1641781528..' \ + -H 'Sec-Fetch-Dest: empty' \ + -H 'Sec-Fetch-Mode: cors' \ + -H 'Sec-Fetch-Site: same-origin' \ + -H 'Pragma: no-cache' \ + -H 'Cache-Control: no-cache' \ + -d '{ + "OriginFromDate":"2022-01-10T00:00:00.000Z", + "OriginToDate":"2022-01-31T00:00:00.000Z", + "DestinationFromDate":null, + "DestinationToDate":null, + "OriginState":["OH"], + "OriginRadius":50, + "DestinationState":[], + "DestinationRadius":50, + "EquipmentTypes":["STRAIGHT TRUCK","str truck w/ lift gate"], + "MaxMilesLimit":null, + "MaxNumberOfStopsLimit":null, + "MaxWeightLimit":null, + "MinMilesLimit":null, + "SavedSearchId":2956 + }' diff --git a/main.go b/main.go index 5cd6810..d25d2c4 100644 --- a/main.go +++ b/main.go @@ -3,6 +3,7 @@ package main import ( "errors" "fmt" + "local/truckstop/broker" "local/truckstop/config" "time" ) @@ -27,6 +28,23 @@ func _main() error { } func once() error { - states := config.Get().States - return errors.New("not impl" + fmt.Sprint(states)) + jobs, err := getJobs() + if err != nil { + return err + } + return errors.New("not impl" + fmt.Sprint(jobs)) +} + +func getJobs() ([]broker.Job, error) { + states := config.Get().States + brokers := []broker.Broker{broker.NewNTGVision().WithMock()} + jobs := []broker.Job{} + for _, broker := range brokers { + somejobs, err := broker.Search(states) + if err != nil { + return nil, err + } + jobs = append(jobs, somejobs...) + } + return jobs, nil }