From fa37e1f61883679e4fc298523432da98b31b6a72 Mon Sep 17 00:00:00 2001 From: Jay Date: Tue, 18 Jun 2019 04:50:31 +0800 Subject: [PATCH] Integrate Telenav Traffic Design and traffic_updater implementation (#18) feat: Define thrift protocol with traffic service and implement logic which generates traffic update file for OSRM - OSRM with telenav traffic architecture - Define traffic protocol in thrift and generate de-coding code - Implement logic to pull result from traffic server and generate csv which could be used for OSRM customization Closes #1, #2, #3 --- .../osrm-release-deployment-pipeline.mmd | 18 + .../osrm-release-deployment-pipeline.mmd.png | Bin 0 -> 41742 bytes ...osrm-with-telenav-traffic-architecture.mmd | 24 + ...-with-telenav-traffic-architecture.mmd.png | Bin 0 -> 17747 bytes .../osrm-with-traffic-startup-flow-chart.mmd | 31 + ...rm-with-traffic-startup-flow-chart.mmd.png | Bin 0 -> 83563 bytes docs/design/graph/puppeteer-config.json | 3 + docs/design/osrm-with-telenav-traffic.md | 23 + traffic_updater/.gitignore | 5 + traffic_updater/README.md | 37 + .../go/gen-go/proxy/GoUnusedProtection__.go | 7 + .../go/gen-go/proxy/proxy-consts.go | 24 + traffic_updater/go/gen-go/proxy/proxy.go | 836 ++++++++++++++++++ .../proxy_service-remote.go | 176 ++++ .../osrm_traffic_updater.go | 127 +++ traffic_updater/proxy.thrift | 13 + 16 files changed, 1324 insertions(+) create mode 100644 docs/design/graph/osrm-release-deployment-pipeline.mmd create mode 100644 docs/design/graph/osrm-release-deployment-pipeline.mmd.png create mode 100644 docs/design/graph/osrm-with-telenav-traffic-architecture.mmd create mode 100644 docs/design/graph/osrm-with-telenav-traffic-architecture.mmd.png create mode 100644 docs/design/graph/osrm-with-traffic-startup-flow-chart.mmd create mode 100644 docs/design/graph/osrm-with-traffic-startup-flow-chart.mmd.png create mode 100644 docs/design/graph/puppeteer-config.json create mode 100644 docs/design/osrm-with-telenav-traffic.md create mode 100644 traffic_updater/.gitignore create mode 100644 traffic_updater/README.md create mode 100644 traffic_updater/go/gen-go/proxy/GoUnusedProtection__.go create mode 100644 traffic_updater/go/gen-go/proxy/proxy-consts.go create mode 100644 traffic_updater/go/gen-go/proxy/proxy.go create mode 100755 traffic_updater/go/gen-go/proxy/proxy_service-remote/proxy_service-remote.go create mode 100644 traffic_updater/go/osrm_traffic_updater/osrm_traffic_updater.go create mode 100644 traffic_updater/proxy.thrift diff --git a/docs/design/graph/osrm-release-deployment-pipeline.mmd b/docs/design/graph/osrm-release-deployment-pipeline.mmd new file mode 100644 index 000000000..750ad7349 --- /dev/null +++ b/docs/design/graph/osrm-release-deployment-pipeline.mmd @@ -0,0 +1,18 @@ + +sequenceDiagram + participant U as User + participant J as Jenkins + participant D as DockerRegistry + participant K as Kubernetes + + U ->>+ J: Build OSRM docker + Note over U,J: include or NOT include mapdata + J ->>- D: Push image to registry + J ->> U: Build done + + U ->> K: Trigger deployment by Kubernetes + Loop e.g. every 5 minutes + K ->> K: Blue/Green deploy based on docker image + note over K: update traffic when container startup + end + diff --git a/docs/design/graph/osrm-release-deployment-pipeline.mmd.png b/docs/design/graph/osrm-release-deployment-pipeline.mmd.png new file mode 100644 index 0000000000000000000000000000000000000000..f76d3dac21fe3350a785ffc129414639dcdcb15c GIT binary patch literal 41742 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%0ANPpkx93aEbkNV`xj?N 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 RO2MB~$Ir+lOI^D2-vEk_ye9wv literal 0 HcmV?d00001 diff --git a/docs/design/graph/osrm-with-telenav-traffic-architecture.mmd b/docs/design/graph/osrm-with-telenav-traffic-architecture.mmd new file mode 100644 index 000000000..bd1450e24 --- /dev/null +++ b/docs/design/graph/osrm-with-telenav-traffic-architecture.mmd @@ -0,0 +1,24 @@ +%% Call below command to convert .mmd to .png +%% Adjust -w or -H if necessary +%% mmdc -p puppeteer-config.json -i osrm-with-telenav-traffic-architecture.mmd -o osrm-with-telenav-traffic-architecture.mmd.png + +graph LR + +Title[OSRM with Telenav Traffic Architecture] +Title-->User +style Title fill:#FFF,stroke:#FFF +linkStyle 0 stroke:#FFF,stroke-width:0; + +User["User"] -- request --> OSRM_ROUTED["osrm-routed"] + +subgraph OSRM Containers +OSRM_ROUTED +OSRM_Traffic_Updater["OSRMTrafficUpdater"] +style OSRM_Traffic_Updater fill:#acbfff,stroke-dasharray: 5, 5 +end + +OSRM_Traffic_Updater -- RPC --> TrafficProxy["TrafficProxy"] +subgraph Traffic Containers +TrafficProxy +style TrafficProxy fill:#acbfff,stroke-dasharray: 5, 5 +end diff --git a/docs/design/graph/osrm-with-telenav-traffic-architecture.mmd.png b/docs/design/graph/osrm-with-telenav-traffic-architecture.mmd.png new file mode 100644 index 0000000000000000000000000000000000000000..4364811dfd0edfc132b721824983dbbb54bb6af9 GIT binary patch literal 17747 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 z�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 literal 0 HcmV?d00001 diff --git a/docs/design/graph/osrm-with-traffic-startup-flow-chart.mmd b/docs/design/graph/osrm-with-traffic-startup-flow-chart.mmd new file mode 100644 index 000000000..5551361cf --- /dev/null +++ b/docs/design/graph/osrm-with-traffic-startup-flow-chart.mmd @@ -0,0 +1,31 @@ +%% Call below command to convert .mmd to .png +%% Adjust -w or -H if necessary +%% mmdc -p puppeteer-config.json -i osrm-with-traffic-startup-flow-chart.mmd -o osrm-with-traffic-startup-flow-chart.mmd.png + +graph TD + +Title[OSRM with Telenav Traffic Container Startup Flow Chart] +Title-->Start +style Title fill:#FFF,stroke:#FFF +linkStyle 0 stroke:#FFF,stroke-width:0; + +Start("Start") --> PrepareCompiledMapdata["Prepare Compile Mapdata

- NA compile mapdata size based on OSM: about 43 GB

- Way 1: Package compiled mapdata inside the docker image

- Way 2: Pull compiled mapdata from network when startup the container "] +style PrepareCompiledMapdata fill:#acbfff,stroke-dasharray: 5, 5 + +PrepareCompiledMapdata --> ConnectTrafficProxy["OSRMTrafficUpdate Connect TrafficProxy by RPC"] + +subgraph OSRM Traffic Updater +ConnectTrafficProxy --> PullLatestTraffic["Pull latest traffic(from node, to node, speed) of full region"] +PullLatestTraffic --> WriteToCSV["Write to traffic.csv(as OSRM format)"] +WriteToCSV --> ExitOSRMTrafficUpdater["Exit ExitOSRMTrafficUpdater"] +end + +subgraph OSRM customize +ExitOSRMTrafficUpdater --> OSRMCustomize["Run osrm-customize on mapdata with traffic.csv"] +end + +subgraph OSRM routed +OSRMCustomize --> OSRMRouted["Run osrm-routed based on customized mapdata"] +end + +OSRMRouted --> End("End") \ No newline at end of file diff --git a/docs/design/graph/osrm-with-traffic-startup-flow-chart.mmd.png b/docs/design/graph/osrm-with-traffic-startup-flow-chart.mmd.png new file mode 100644 index 0000000000000000000000000000000000000000..42cf5cd6745c1b4dd5e6f5369ad75f2f648831a5 GIT binary patch literal 83563 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≤C^Ju#(>6}Qo&j!v*CDZf-xW}dC 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 literal 0 HcmV?d00001 diff --git a/docs/design/graph/puppeteer-config.json b/docs/design/graph/puppeteer-config.json new file mode 100644 index 000000000..3201af7b7 --- /dev/null +++ b/docs/design/graph/puppeteer-config.json @@ -0,0 +1,3 @@ +{ + "args": ["--no-sandbox"] +} diff --git a/docs/design/osrm-with-telenav-traffic.md b/docs/design/osrm-with-telenav-traffic.md new file mode 100644 index 000000000..fb0f6a8bc --- /dev/null +++ b/docs/design/osrm-with-telenav-traffic.md @@ -0,0 +1,23 @@ +# OSRM with Telenav Traffic Design (Draft) + +## Architecture +![osrm-with-telenav-traffic-architecture](./graph/osrm-with-telenav-traffic-architecture.mmd.png) + +### OSRMTrafficUpdater(need to implement) +- as client +- connect `TrafficProxy` by `RPC` +- convert contents from `RPC` protocol to `OSRM` required `csv` format, then write to file + +### TrafficProxy(need to implement) +- as server +- provide traffic contents by region +- contents include at least `from node, to node, speed`(both `from node` and `to node` are come from original mapdata) +- known issues/questions: + - can not compile `OSM` mapdata to traffic graph? + + +## OSRM with Traffic Startup Flow +![osrm-with-traffic-startup-flow-chart](./graph/osrm-with-traffic-startup-flow-chart.mmd.png) + +## Release and Deployment Pipeline +![osrm-release-deployment-pipeline](./graph/osrm-release-deployment-pipeline.mmd.png) \ No newline at end of file diff --git a/traffic_updater/.gitignore b/traffic_updater/.gitignore new file mode 100644 index 000000000..19f47cebb --- /dev/null +++ b/traffic_updater/.gitignore @@ -0,0 +1,5 @@ + +*.py[cod] + +traffic.csv +*/traffic.csv diff --git a/traffic_updater/README.md b/traffic_updater/README.md new file mode 100644 index 000000000..82106fb5a --- /dev/null +++ b/traffic_updater/README.md @@ -0,0 +1,37 @@ +# OSRM Traffic Updater +The **OSRM Traffic Updater** is designed for pull traffic data from **Traffic Proxy(Telenav)** then dump to OSRM required `traffic.csv`. Refer to [OSRM with Telenav Traffic Design](../docs/design/osrm-with-telenav-traffic.md) and [OSRM Traffic](https://github.com/Project-OSRM/osrm-backend/wiki/Traffic) for more details. +We have implemented both `Python` and `Go` version. Both of them have same function(pull data then dump to csv), but the `Go` implementation is about **23 times** faster than `Python` implementation. So strongly recommended to use `Go` implementation as preference. +- E.g. `6727490` lines traffic of NA region + - `Go` Implementation: about `9 seconds` + - `Python` Implementation: about `210 seconds` + +## RPC Protocol +See [proxy.thrift](proxy.thrift) for details. + +## Python Implementation +The `python` based implementation has been deprecated due to bad performance. See [Deprecated Python Implementation Codes](https://github.com/Telenav/osrm-backend/blob/b4eb73f2d307fd4dbd8b8610bbc2a68c3b6ab1ae/traffic_updater/python/osrm_traffic_updater.py#L57) if you'd like to see code details. + +## Go Implementation +### Requirements +- `go version go1.12.5 linux/amd64` +- `thrift 0.12.0` + - clone `thrift` from `github.com/apache/thrift`, then checkout branch `0.12.0` +- change `thrift` imports in generated codes `gen-go/proxy` + - `git.apache.org/thrift.git/lib/go/thrift` -> `github.com/apache/thrift/lib/go/thrift` + + +### Usage +```bash +$ cd $GOPATH +$ go install github.com/Telenav/osrm-backend/traffic_updater/go/osrm_traffic_updater +$ ./bin/osrm_traffic_updater -h +Usage of ./bin/osrm_traffic_updater: + -c string + traffic proxy ip address (default "127.0.0.1") + -d use high precision speeds, i.e. decimal (default true) + -f string + OSRM traffic csv file (default "traffic.csv") + -p int + traffic proxy listening port (default 6666) +``` + diff --git a/traffic_updater/go/gen-go/proxy/GoUnusedProtection__.go b/traffic_updater/go/gen-go/proxy/GoUnusedProtection__.go new file mode 100644 index 000000000..701886b7f --- /dev/null +++ b/traffic_updater/go/gen-go/proxy/GoUnusedProtection__.go @@ -0,0 +1,7 @@ +// Autogenerated by Thrift Compiler (0.12.0) +// DO NOT EDIT UNLESS YOU ARE SURE THAT YOU KNOW WHAT YOU ARE DOING + +package proxy + +var GoUnusedProtection__ int; + diff --git a/traffic_updater/go/gen-go/proxy/proxy-consts.go b/traffic_updater/go/gen-go/proxy/proxy-consts.go new file mode 100644 index 000000000..93d2c3c55 --- /dev/null +++ b/traffic_updater/go/gen-go/proxy/proxy-consts.go @@ -0,0 +1,24 @@ +// Autogenerated by Thrift Compiler (0.12.0) +// DO NOT EDIT UNLESS YOU ARE SURE THAT YOU KNOW WHAT YOU ARE DOING + +package proxy + +import ( + "bytes" + "context" + "reflect" + "fmt" + "github.com/apache/thrift/lib/go/thrift" +) + +// (needed to ensure safety because of naive import list construction.) +var _ = thrift.ZERO +var _ = fmt.Printf +var _ = context.Background +var _ = reflect.DeepEqual +var _ = bytes.Equal + + +func init() { +} + diff --git a/traffic_updater/go/gen-go/proxy/proxy.go b/traffic_updater/go/gen-go/proxy/proxy.go new file mode 100644 index 000000000..b93fc4397 --- /dev/null +++ b/traffic_updater/go/gen-go/proxy/proxy.go @@ -0,0 +1,836 @@ +// Autogenerated by Thrift Compiler (0.12.0) +// DO NOT EDIT UNLESS YOU ARE SURE THAT YOU KNOW WHAT YOU ARE DOING + +package proxy + +import ( + "bytes" + "context" + "reflect" + "fmt" + "github.com/apache/thrift/lib/go/thrift" +) + +// (needed to ensure safety because of naive import list construction.) +var _ = thrift.ZERO +var _ = fmt.Printf +var _ = context.Background +var _ = reflect.DeepEqual +var _ = bytes.Equal + +// Attributes: +// - FromId +// - ToId +// - WayId +// - Speed +// - TrafficLevel +type Flow struct { + FromId int64 `thrift:"fromId,1,required" db:"fromId" json:"fromId"` + ToId int64 `thrift:"toId,2,required" db:"toId" json:"toId"` + WayId int64 `thrift:"wayId,3,required" db:"wayId" json:"wayId"` + Speed float64 `thrift:"speed,4,required" db:"speed" json:"speed"` + TrafficLevel int32 `thrift:"trafficLevel,5,required" db:"trafficLevel" json:"trafficLevel"` +} + +func NewFlow() *Flow { + return &Flow{} +} + + +func (p *Flow) GetFromId() int64 { + return p.FromId +} + +func (p *Flow) GetToId() int64 { + return p.ToId +} + +func (p *Flow) GetWayId() int64 { + return p.WayId +} + +func (p *Flow) GetSpeed() float64 { + return p.Speed +} + +func (p *Flow) GetTrafficLevel() int32 { + return p.TrafficLevel +} +func (p *Flow) Read(iprot thrift.TProtocol) error { + if _, err := iprot.ReadStructBegin(); err != nil { + return thrift.PrependError(fmt.Sprintf("%T read error: ", p), err) + } + + var issetFromId bool = false; + var issetToId bool = false; + var issetWayId bool = false; + var issetSpeed bool = false; + var issetTrafficLevel bool = false; + + for { + _, fieldTypeId, fieldId, err := iprot.ReadFieldBegin() + if err != nil { + return thrift.PrependError(fmt.Sprintf("%T field %d read error: ", p, fieldId), err) + } + if fieldTypeId == thrift.STOP { break; } + switch fieldId { + case 1: + if fieldTypeId == thrift.I64 { + if err := p.ReadField1(iprot); err != nil { + return err + } + issetFromId = true + } else { + if err := iprot.Skip(fieldTypeId); err != nil { + return err + } + } + case 2: + if fieldTypeId == thrift.I64 { + if err := p.ReadField2(iprot); err != nil { + return err + } + issetToId = true + } else { + if err := iprot.Skip(fieldTypeId); err != nil { + return err + } + } + case 3: + if fieldTypeId == thrift.I64 { + if err := p.ReadField3(iprot); err != nil { + return err + } + issetWayId = true + } else { + if err := iprot.Skip(fieldTypeId); err != nil { + return err + } + } + case 4: + if fieldTypeId == thrift.DOUBLE { + if err := p.ReadField4(iprot); err != nil { + return err + } + issetSpeed = true + } else { + if err := iprot.Skip(fieldTypeId); err != nil { + return err + } + } + case 5: + if fieldTypeId == thrift.I32 { + if err := p.ReadField5(iprot); err != nil { + return err + } + issetTrafficLevel = true + } else { + if err := iprot.Skip(fieldTypeId); err != nil { + return err + } + } + default: + if err := iprot.Skip(fieldTypeId); err != nil { + return err + } + } + if err := iprot.ReadFieldEnd(); err != nil { + return err + } + } + if err := iprot.ReadStructEnd(); err != nil { + return thrift.PrependError(fmt.Sprintf("%T read struct end error: ", p), err) + } + if !issetFromId{ + return thrift.NewTProtocolExceptionWithType(thrift.INVALID_DATA, fmt.Errorf("Required field FromId is not set")); + } + if !issetToId{ + return thrift.NewTProtocolExceptionWithType(thrift.INVALID_DATA, fmt.Errorf("Required field ToId is not set")); + } + if !issetWayId{ + return thrift.NewTProtocolExceptionWithType(thrift.INVALID_DATA, fmt.Errorf("Required field WayId is not set")); + } + if !issetSpeed{ + return thrift.NewTProtocolExceptionWithType(thrift.INVALID_DATA, fmt.Errorf("Required field Speed is not set")); + } + if !issetTrafficLevel{ + return thrift.NewTProtocolExceptionWithType(thrift.INVALID_DATA, fmt.Errorf("Required field TrafficLevel is not set")); + } + return nil +} + +func (p *Flow) ReadField1(iprot thrift.TProtocol) error { + if v, err := iprot.ReadI64(); err != nil { + return thrift.PrependError("error reading field 1: ", err) +} else { + p.FromId = v +} + return nil +} + +func (p *Flow) ReadField2(iprot thrift.TProtocol) error { + if v, err := iprot.ReadI64(); err != nil { + return thrift.PrependError("error reading field 2: ", err) +} else { + p.ToId = v +} + return nil +} + +func (p *Flow) ReadField3(iprot thrift.TProtocol) error { + if v, err := iprot.ReadI64(); err != nil { + return thrift.PrependError("error reading field 3: ", err) +} else { + p.WayId = v +} + return nil +} + +func (p *Flow) ReadField4(iprot thrift.TProtocol) error { + if v, err := iprot.ReadDouble(); err != nil { + return thrift.PrependError("error reading field 4: ", err) +} else { + p.Speed = v +} + return nil +} + +func (p *Flow) ReadField5(iprot thrift.TProtocol) error { + if v, err := iprot.ReadI32(); err != nil { + return thrift.PrependError("error reading field 5: ", err) +} else { + p.TrafficLevel = v +} + return nil +} + +func (p *Flow) Write(oprot thrift.TProtocol) error { + if err := oprot.WriteStructBegin("Flow"); err != nil { + return thrift.PrependError(fmt.Sprintf("%T write struct begin error: ", p), err) } + if p != nil { + if err := p.writeField1(oprot); err != nil { return err } + if err := p.writeField2(oprot); err != nil { return err } + if err := p.writeField3(oprot); err != nil { return err } + if err := p.writeField4(oprot); err != nil { return err } + if err := p.writeField5(oprot); err != nil { return err } + } + if err := oprot.WriteFieldStop(); err != nil { + return thrift.PrependError("write field stop error: ", err) } + if err := oprot.WriteStructEnd(); err != nil { + return thrift.PrependError("write struct stop error: ", err) } + return nil +} + +func (p *Flow) writeField1(oprot thrift.TProtocol) (err error) { + if err := oprot.WriteFieldBegin("fromId", thrift.I64, 1); err != nil { + return thrift.PrependError(fmt.Sprintf("%T write field begin error 1:fromId: ", p), err) } + if err := oprot.WriteI64(int64(p.FromId)); err != nil { + return thrift.PrependError(fmt.Sprintf("%T.fromId (1) field write error: ", p), err) } + if err := oprot.WriteFieldEnd(); err != nil { + return thrift.PrependError(fmt.Sprintf("%T write field end error 1:fromId: ", p), err) } + return err +} + +func (p *Flow) writeField2(oprot thrift.TProtocol) (err error) { + if err := oprot.WriteFieldBegin("toId", thrift.I64, 2); err != nil { + return thrift.PrependError(fmt.Sprintf("%T write field begin error 2:toId: ", p), err) } + if err := oprot.WriteI64(int64(p.ToId)); err != nil { + return thrift.PrependError(fmt.Sprintf("%T.toId (2) field write error: ", p), err) } + if err := oprot.WriteFieldEnd(); err != nil { + return thrift.PrependError(fmt.Sprintf("%T write field end error 2:toId: ", p), err) } + return err +} + +func (p *Flow) writeField3(oprot thrift.TProtocol) (err error) { + if err := oprot.WriteFieldBegin("wayId", thrift.I64, 3); err != nil { + return thrift.PrependError(fmt.Sprintf("%T write field begin error 3:wayId: ", p), err) } + if err := oprot.WriteI64(int64(p.WayId)); err != nil { + return thrift.PrependError(fmt.Sprintf("%T.wayId (3) field write error: ", p), err) } + if err := oprot.WriteFieldEnd(); err != nil { + return thrift.PrependError(fmt.Sprintf("%T write field end error 3:wayId: ", p), err) } + return err +} + +func (p *Flow) writeField4(oprot thrift.TProtocol) (err error) { + if err := oprot.WriteFieldBegin("speed", thrift.DOUBLE, 4); err != nil { + return thrift.PrependError(fmt.Sprintf("%T write field begin error 4:speed: ", p), err) } + if err := oprot.WriteDouble(float64(p.Speed)); err != nil { + return thrift.PrependError(fmt.Sprintf("%T.speed (4) field write error: ", p), err) } + if err := oprot.WriteFieldEnd(); err != nil { + return thrift.PrependError(fmt.Sprintf("%T write field end error 4:speed: ", p), err) } + return err +} + +func (p *Flow) writeField5(oprot thrift.TProtocol) (err error) { + if err := oprot.WriteFieldBegin("trafficLevel", thrift.I32, 5); err != nil { + return thrift.PrependError(fmt.Sprintf("%T write field begin error 5:trafficLevel: ", p), err) } + if err := oprot.WriteI32(int32(p.TrafficLevel)); err != nil { + return thrift.PrependError(fmt.Sprintf("%T.trafficLevel (5) field write error: ", p), err) } + if err := oprot.WriteFieldEnd(); err != nil { + return thrift.PrependError(fmt.Sprintf("%T write field end error 5:trafficLevel: ", p), err) } + return err +} + +func (p *Flow) String() string { + if p == nil { + return "" + } + return fmt.Sprintf("Flow(%+v)", *p) +} + +type ProxyService interface { + GetAllFlows(ctx context.Context) (r []*Flow, err error) + // Parameters: + // - WayId + GetFlowById(ctx context.Context, wayId int64) (r *Flow, err error) +} + +type ProxyServiceClient struct { + c thrift.TClient +} + +func NewProxyServiceClientFactory(t thrift.TTransport, f thrift.TProtocolFactory) *ProxyServiceClient { + return &ProxyServiceClient{ + c: thrift.NewTStandardClient(f.GetProtocol(t), f.GetProtocol(t)), + } +} + +func NewProxyServiceClientProtocol(t thrift.TTransport, iprot thrift.TProtocol, oprot thrift.TProtocol) *ProxyServiceClient { + return &ProxyServiceClient{ + c: thrift.NewTStandardClient(iprot, oprot), + } +} + +func NewProxyServiceClient(c thrift.TClient) *ProxyServiceClient { + return &ProxyServiceClient{ + c: c, + } +} + +func (p *ProxyServiceClient) Client_() thrift.TClient { + return p.c +} +func (p *ProxyServiceClient) GetAllFlows(ctx context.Context) (r []*Flow, err error) { + var _args0 ProxyServiceGetAllFlowsArgs + var _result1 ProxyServiceGetAllFlowsResult + if err = p.Client_().Call(ctx, "getAllFlows", &_args0, &_result1); err != nil { + return + } + return _result1.GetSuccess(), nil +} + +// Parameters: +// - WayId +func (p *ProxyServiceClient) GetFlowById(ctx context.Context, wayId int64) (r *Flow, err error) { + var _args2 ProxyServiceGetFlowByIdArgs + _args2.WayId = wayId + var _result3 ProxyServiceGetFlowByIdResult + if err = p.Client_().Call(ctx, "getFlowById", &_args2, &_result3); err != nil { + return + } + return _result3.GetSuccess(), nil +} + +type ProxyServiceProcessor struct { + processorMap map[string]thrift.TProcessorFunction + handler ProxyService +} + +func (p *ProxyServiceProcessor) AddToProcessorMap(key string, processor thrift.TProcessorFunction) { + p.processorMap[key] = processor +} + +func (p *ProxyServiceProcessor) GetProcessorFunction(key string) (processor thrift.TProcessorFunction, ok bool) { + processor, ok = p.processorMap[key] + return processor, ok +} + +func (p *ProxyServiceProcessor) ProcessorMap() map[string]thrift.TProcessorFunction { + return p.processorMap +} + +func NewProxyServiceProcessor(handler ProxyService) *ProxyServiceProcessor { + + self4 := &ProxyServiceProcessor{handler:handler, processorMap:make(map[string]thrift.TProcessorFunction)} + self4.processorMap["getAllFlows"] = &proxyServiceProcessorGetAllFlows{handler:handler} + self4.processorMap["getFlowById"] = &proxyServiceProcessorGetFlowById{handler:handler} +return self4 +} + +func (p *ProxyServiceProcessor) Process(ctx context.Context, iprot, oprot thrift.TProtocol) (success bool, err thrift.TException) { + name, _, seqId, err := iprot.ReadMessageBegin() + if err != nil { return false, err } + if processor, ok := p.GetProcessorFunction(name); ok { + return processor.Process(ctx, seqId, iprot, oprot) + } + iprot.Skip(thrift.STRUCT) + iprot.ReadMessageEnd() + x5 := thrift.NewTApplicationException(thrift.UNKNOWN_METHOD, "Unknown function " + name) + oprot.WriteMessageBegin(name, thrift.EXCEPTION, seqId) + x5.Write(oprot) + oprot.WriteMessageEnd() + oprot.Flush(ctx) + return false, x5 + +} + +type proxyServiceProcessorGetAllFlows struct { + handler ProxyService +} + +func (p *proxyServiceProcessorGetAllFlows) Process(ctx context.Context, seqId int32, iprot, oprot thrift.TProtocol) (success bool, err thrift.TException) { + args := ProxyServiceGetAllFlowsArgs{} + if err = args.Read(iprot); err != nil { + iprot.ReadMessageEnd() + x := thrift.NewTApplicationException(thrift.PROTOCOL_ERROR, err.Error()) + oprot.WriteMessageBegin("getAllFlows", thrift.EXCEPTION, seqId) + x.Write(oprot) + oprot.WriteMessageEnd() + oprot.Flush(ctx) + return false, err + } + + iprot.ReadMessageEnd() + result := ProxyServiceGetAllFlowsResult{} +var retval []*Flow + var err2 error + if retval, err2 = p.handler.GetAllFlows(ctx); err2 != nil { + x := thrift.NewTApplicationException(thrift.INTERNAL_ERROR, "Internal error processing getAllFlows: " + err2.Error()) + oprot.WriteMessageBegin("getAllFlows", thrift.EXCEPTION, seqId) + x.Write(oprot) + oprot.WriteMessageEnd() + oprot.Flush(ctx) + return true, err2 + } else { + result.Success = retval +} + if err2 = oprot.WriteMessageBegin("getAllFlows", thrift.REPLY, seqId); err2 != nil { + err = err2 + } + if err2 = result.Write(oprot); err == nil && err2 != nil { + err = err2 + } + if err2 = oprot.WriteMessageEnd(); err == nil && err2 != nil { + err = err2 + } + if err2 = oprot.Flush(ctx); err == nil && err2 != nil { + err = err2 + } + if err != nil { + return + } + return true, err +} + +type proxyServiceProcessorGetFlowById struct { + handler ProxyService +} + +func (p *proxyServiceProcessorGetFlowById) Process(ctx context.Context, seqId int32, iprot, oprot thrift.TProtocol) (success bool, err thrift.TException) { + args := ProxyServiceGetFlowByIdArgs{} + if err = args.Read(iprot); err != nil { + iprot.ReadMessageEnd() + x := thrift.NewTApplicationException(thrift.PROTOCOL_ERROR, err.Error()) + oprot.WriteMessageBegin("getFlowById", thrift.EXCEPTION, seqId) + x.Write(oprot) + oprot.WriteMessageEnd() + oprot.Flush(ctx) + return false, err + } + + iprot.ReadMessageEnd() + result := ProxyServiceGetFlowByIdResult{} +var retval *Flow + var err2 error + if retval, err2 = p.handler.GetFlowById(ctx, args.WayId); err2 != nil { + x := thrift.NewTApplicationException(thrift.INTERNAL_ERROR, "Internal error processing getFlowById: " + err2.Error()) + oprot.WriteMessageBegin("getFlowById", thrift.EXCEPTION, seqId) + x.Write(oprot) + oprot.WriteMessageEnd() + oprot.Flush(ctx) + return true, err2 + } else { + result.Success = retval +} + if err2 = oprot.WriteMessageBegin("getFlowById", thrift.REPLY, seqId); err2 != nil { + err = err2 + } + if err2 = result.Write(oprot); err == nil && err2 != nil { + err = err2 + } + if err2 = oprot.WriteMessageEnd(); err == nil && err2 != nil { + err = err2 + } + if err2 = oprot.Flush(ctx); err == nil && err2 != nil { + err = err2 + } + if err != nil { + return + } + return true, err +} + + +// HELPER FUNCTIONS AND STRUCTURES + +type ProxyServiceGetAllFlowsArgs struct { +} + +func NewProxyServiceGetAllFlowsArgs() *ProxyServiceGetAllFlowsArgs { + return &ProxyServiceGetAllFlowsArgs{} +} + +func (p *ProxyServiceGetAllFlowsArgs) Read(iprot thrift.TProtocol) error { + if _, err := iprot.ReadStructBegin(); err != nil { + return thrift.PrependError(fmt.Sprintf("%T read error: ", p), err) + } + + + for { + _, fieldTypeId, fieldId, err := iprot.ReadFieldBegin() + if err != nil { + return thrift.PrependError(fmt.Sprintf("%T field %d read error: ", p, fieldId), err) + } + if fieldTypeId == thrift.STOP { break; } + if err := iprot.Skip(fieldTypeId); err != nil { + return err + } + if err := iprot.ReadFieldEnd(); err != nil { + return err + } + } + if err := iprot.ReadStructEnd(); err != nil { + return thrift.PrependError(fmt.Sprintf("%T read struct end error: ", p), err) + } + return nil +} + +func (p *ProxyServiceGetAllFlowsArgs) Write(oprot thrift.TProtocol) error { + if err := oprot.WriteStructBegin("getAllFlows_args"); err != nil { + return thrift.PrependError(fmt.Sprintf("%T write struct begin error: ", p), err) } + if p != nil { + } + if err := oprot.WriteFieldStop(); err != nil { + return thrift.PrependError("write field stop error: ", err) } + if err := oprot.WriteStructEnd(); err != nil { + return thrift.PrependError("write struct stop error: ", err) } + return nil +} + +func (p *ProxyServiceGetAllFlowsArgs) String() string { + if p == nil { + return "" + } + return fmt.Sprintf("ProxyServiceGetAllFlowsArgs(%+v)", *p) +} + +// Attributes: +// - Success +type ProxyServiceGetAllFlowsResult struct { + Success []*Flow `thrift:"success,0" db:"success" json:"success,omitempty"` +} + +func NewProxyServiceGetAllFlowsResult() *ProxyServiceGetAllFlowsResult { + return &ProxyServiceGetAllFlowsResult{} +} + +var ProxyServiceGetAllFlowsResult_Success_DEFAULT []*Flow + +func (p *ProxyServiceGetAllFlowsResult) GetSuccess() []*Flow { + return p.Success +} +func (p *ProxyServiceGetAllFlowsResult) IsSetSuccess() bool { + return p.Success != nil +} + +func (p *ProxyServiceGetAllFlowsResult) Read(iprot thrift.TProtocol) error { + if _, err := iprot.ReadStructBegin(); err != nil { + return thrift.PrependError(fmt.Sprintf("%T read error: ", p), err) + } + + + for { + _, fieldTypeId, fieldId, err := iprot.ReadFieldBegin() + if err != nil { + return thrift.PrependError(fmt.Sprintf("%T field %d read error: ", p, fieldId), err) + } + if fieldTypeId == thrift.STOP { break; } + switch fieldId { + case 0: + if fieldTypeId == thrift.LIST { + if err := p.ReadField0(iprot); err != nil { + return err + } + } else { + if err := iprot.Skip(fieldTypeId); err != nil { + return err + } + } + default: + if err := iprot.Skip(fieldTypeId); err != nil { + return err + } + } + if err := iprot.ReadFieldEnd(); err != nil { + return err + } + } + if err := iprot.ReadStructEnd(); err != nil { + return thrift.PrependError(fmt.Sprintf("%T read struct end error: ", p), err) + } + return nil +} + +func (p *ProxyServiceGetAllFlowsResult) ReadField0(iprot thrift.TProtocol) error { + _, size, err := iprot.ReadListBegin() + if err != nil { + return thrift.PrependError("error reading list begin: ", err) + } + tSlice := make([]*Flow, 0, size) + p.Success = tSlice + for i := 0; i < size; i ++ { + _elem6 := &Flow{} + if err := _elem6.Read(iprot); err != nil { + return thrift.PrependError(fmt.Sprintf("%T error reading struct: ", _elem6), err) + } + p.Success = append(p.Success, _elem6) + } + if err := iprot.ReadListEnd(); err != nil { + return thrift.PrependError("error reading list end: ", err) + } + return nil +} + +func (p *ProxyServiceGetAllFlowsResult) Write(oprot thrift.TProtocol) error { + if err := oprot.WriteStructBegin("getAllFlows_result"); err != nil { + return thrift.PrependError(fmt.Sprintf("%T write struct begin error: ", p), err) } + if p != nil { + if err := p.writeField0(oprot); err != nil { return err } + } + if err := oprot.WriteFieldStop(); err != nil { + return thrift.PrependError("write field stop error: ", err) } + if err := oprot.WriteStructEnd(); err != nil { + return thrift.PrependError("write struct stop error: ", err) } + return nil +} + +func (p *ProxyServiceGetAllFlowsResult) writeField0(oprot thrift.TProtocol) (err error) { + if p.IsSetSuccess() { + if err := oprot.WriteFieldBegin("success", thrift.LIST, 0); err != nil { + return thrift.PrependError(fmt.Sprintf("%T write field begin error 0:success: ", p), err) } + if err := oprot.WriteListBegin(thrift.STRUCT, len(p.Success)); err != nil { + return thrift.PrependError("error writing list begin: ", err) + } + for _, v := range p.Success { + if err := v.Write(oprot); err != nil { + return thrift.PrependError(fmt.Sprintf("%T error writing struct: ", v), err) + } + } + if err := oprot.WriteListEnd(); err != nil { + return thrift.PrependError("error writing list end: ", err) + } + if err := oprot.WriteFieldEnd(); err != nil { + return thrift.PrependError(fmt.Sprintf("%T write field end error 0:success: ", p), err) } + } + return err +} + +func (p *ProxyServiceGetAllFlowsResult) String() string { + if p == nil { + return "" + } + return fmt.Sprintf("ProxyServiceGetAllFlowsResult(%+v)", *p) +} + +// Attributes: +// - WayId +type ProxyServiceGetFlowByIdArgs struct { + WayId int64 `thrift:"wayId,1" db:"wayId" json:"wayId"` +} + +func NewProxyServiceGetFlowByIdArgs() *ProxyServiceGetFlowByIdArgs { + return &ProxyServiceGetFlowByIdArgs{} +} + + +func (p *ProxyServiceGetFlowByIdArgs) GetWayId() int64 { + return p.WayId +} +func (p *ProxyServiceGetFlowByIdArgs) Read(iprot thrift.TProtocol) error { + if _, err := iprot.ReadStructBegin(); err != nil { + return thrift.PrependError(fmt.Sprintf("%T read error: ", p), err) + } + + + for { + _, fieldTypeId, fieldId, err := iprot.ReadFieldBegin() + if err != nil { + return thrift.PrependError(fmt.Sprintf("%T field %d read error: ", p, fieldId), err) + } + if fieldTypeId == thrift.STOP { break; } + switch fieldId { + case 1: + if fieldTypeId == thrift.I64 { + if err := p.ReadField1(iprot); err != nil { + return err + } + } else { + if err := iprot.Skip(fieldTypeId); err != nil { + return err + } + } + default: + if err := iprot.Skip(fieldTypeId); err != nil { + return err + } + } + if err := iprot.ReadFieldEnd(); err != nil { + return err + } + } + if err := iprot.ReadStructEnd(); err != nil { + return thrift.PrependError(fmt.Sprintf("%T read struct end error: ", p), err) + } + return nil +} + +func (p *ProxyServiceGetFlowByIdArgs) ReadField1(iprot thrift.TProtocol) error { + if v, err := iprot.ReadI64(); err != nil { + return thrift.PrependError("error reading field 1: ", err) +} else { + p.WayId = v +} + return nil +} + +func (p *ProxyServiceGetFlowByIdArgs) Write(oprot thrift.TProtocol) error { + if err := oprot.WriteStructBegin("getFlowById_args"); err != nil { + return thrift.PrependError(fmt.Sprintf("%T write struct begin error: ", p), err) } + if p != nil { + if err := p.writeField1(oprot); err != nil { return err } + } + if err := oprot.WriteFieldStop(); err != nil { + return thrift.PrependError("write field stop error: ", err) } + if err := oprot.WriteStructEnd(); err != nil { + return thrift.PrependError("write struct stop error: ", err) } + return nil +} + +func (p *ProxyServiceGetFlowByIdArgs) writeField1(oprot thrift.TProtocol) (err error) { + if err := oprot.WriteFieldBegin("wayId", thrift.I64, 1); err != nil { + return thrift.PrependError(fmt.Sprintf("%T write field begin error 1:wayId: ", p), err) } + if err := oprot.WriteI64(int64(p.WayId)); err != nil { + return thrift.PrependError(fmt.Sprintf("%T.wayId (1) field write error: ", p), err) } + if err := oprot.WriteFieldEnd(); err != nil { + return thrift.PrependError(fmt.Sprintf("%T write field end error 1:wayId: ", p), err) } + return err +} + +func (p *ProxyServiceGetFlowByIdArgs) String() string { + if p == nil { + return "" + } + return fmt.Sprintf("ProxyServiceGetFlowByIdArgs(%+v)", *p) +} + +// Attributes: +// - Success +type ProxyServiceGetFlowByIdResult struct { + Success *Flow `thrift:"success,0" db:"success" json:"success,omitempty"` +} + +func NewProxyServiceGetFlowByIdResult() *ProxyServiceGetFlowByIdResult { + return &ProxyServiceGetFlowByIdResult{} +} + +var ProxyServiceGetFlowByIdResult_Success_DEFAULT *Flow +func (p *ProxyServiceGetFlowByIdResult) GetSuccess() *Flow { + if !p.IsSetSuccess() { + return ProxyServiceGetFlowByIdResult_Success_DEFAULT + } +return p.Success +} +func (p *ProxyServiceGetFlowByIdResult) IsSetSuccess() bool { + return p.Success != nil +} + +func (p *ProxyServiceGetFlowByIdResult) Read(iprot thrift.TProtocol) error { + if _, err := iprot.ReadStructBegin(); err != nil { + return thrift.PrependError(fmt.Sprintf("%T read error: ", p), err) + } + + + for { + _, fieldTypeId, fieldId, err := iprot.ReadFieldBegin() + if err != nil { + return thrift.PrependError(fmt.Sprintf("%T field %d read error: ", p, fieldId), err) + } + if fieldTypeId == thrift.STOP { break; } + switch fieldId { + case 0: + if fieldTypeId == thrift.STRUCT { + if err := p.ReadField0(iprot); err != nil { + return err + } + } else { + if err := iprot.Skip(fieldTypeId); err != nil { + return err + } + } + default: + if err := iprot.Skip(fieldTypeId); err != nil { + return err + } + } + if err := iprot.ReadFieldEnd(); err != nil { + return err + } + } + if err := iprot.ReadStructEnd(); err != nil { + return thrift.PrependError(fmt.Sprintf("%T read struct end error: ", p), err) + } + return nil +} + +func (p *ProxyServiceGetFlowByIdResult) ReadField0(iprot thrift.TProtocol) error { + p.Success = &Flow{} + if err := p.Success.Read(iprot); err != nil { + return thrift.PrependError(fmt.Sprintf("%T error reading struct: ", p.Success), err) + } + return nil +} + +func (p *ProxyServiceGetFlowByIdResult) Write(oprot thrift.TProtocol) error { + if err := oprot.WriteStructBegin("getFlowById_result"); err != nil { + return thrift.PrependError(fmt.Sprintf("%T write struct begin error: ", p), err) } + if p != nil { + if err := p.writeField0(oprot); err != nil { return err } + } + if err := oprot.WriteFieldStop(); err != nil { + return thrift.PrependError("write field stop error: ", err) } + if err := oprot.WriteStructEnd(); err != nil { + return thrift.PrependError("write struct stop error: ", err) } + return nil +} + +func (p *ProxyServiceGetFlowByIdResult) writeField0(oprot thrift.TProtocol) (err error) { + if p.IsSetSuccess() { + if err := oprot.WriteFieldBegin("success", thrift.STRUCT, 0); err != nil { + return thrift.PrependError(fmt.Sprintf("%T write field begin error 0:success: ", p), err) } + if err := p.Success.Write(oprot); err != nil { + return thrift.PrependError(fmt.Sprintf("%T error writing struct: ", p.Success), err) + } + if err := oprot.WriteFieldEnd(); err != nil { + return thrift.PrependError(fmt.Sprintf("%T write field end error 0:success: ", p), err) } + } + return err +} + +func (p *ProxyServiceGetFlowByIdResult) String() string { + if p == nil { + return "" + } + return fmt.Sprintf("ProxyServiceGetFlowByIdResult(%+v)", *p) +} + + diff --git a/traffic_updater/go/gen-go/proxy/proxy_service-remote/proxy_service-remote.go b/traffic_updater/go/gen-go/proxy/proxy_service-remote/proxy_service-remote.go new file mode 100755 index 000000000..b85471185 --- /dev/null +++ b/traffic_updater/go/gen-go/proxy/proxy_service-remote/proxy_service-remote.go @@ -0,0 +1,176 @@ +// Autogenerated by Thrift Compiler (0.12.0) +// DO NOT EDIT UNLESS YOU ARE SURE THAT YOU KNOW WHAT YOU ARE DOING + +package main + +import ( + "context" + "flag" + "fmt" + "math" + "net" + "net/url" + "os" + "strconv" + "strings" + "github.com/apache/thrift/lib/go/thrift" + "proxy" +) + + +func Usage() { + fmt.Fprintln(os.Stderr, "Usage of ", os.Args[0], " [-h host:port] [-u url] [-f[ramed]] function [arg1 [arg2...]]:") + flag.PrintDefaults() + fmt.Fprintln(os.Stderr, "\nFunctions:") + fmt.Fprintln(os.Stderr, " getAllFlows()") + fmt.Fprintln(os.Stderr, " Flow getFlowById(i64 wayId)") + fmt.Fprintln(os.Stderr) + os.Exit(0) +} + +type httpHeaders map[string]string + +func (h httpHeaders) String() string { + var m map[string]string = h + return fmt.Sprintf("%s", m) +} + +func (h httpHeaders) Set(value string) error { + parts := strings.Split(value, ": ") + if len(parts) != 2 { + return fmt.Errorf("header should be of format 'Key: Value'") + } + h[parts[0]] = parts[1] + return nil +} + +func main() { + flag.Usage = Usage + var host string + var port int + var protocol string + var urlString string + var framed bool + var useHttp bool + headers := make(httpHeaders) + var parsedUrl *url.URL + var trans thrift.TTransport + _ = strconv.Atoi + _ = math.Abs + flag.Usage = Usage + flag.StringVar(&host, "h", "localhost", "Specify host and port") + flag.IntVar(&port, "p", 9090, "Specify port") + flag.StringVar(&protocol, "P", "binary", "Specify the protocol (binary, compact, simplejson, json)") + flag.StringVar(&urlString, "u", "", "Specify the url") + flag.BoolVar(&framed, "framed", false, "Use framed transport") + flag.BoolVar(&useHttp, "http", false, "Use http") + flag.Var(headers, "H", "Headers to set on the http(s) request (e.g. -H \"Key: Value\")") + flag.Parse() + + if len(urlString) > 0 { + var err error + parsedUrl, err = url.Parse(urlString) + if err != nil { + fmt.Fprintln(os.Stderr, "Error parsing URL: ", err) + flag.Usage() + } + host = parsedUrl.Host + useHttp = len(parsedUrl.Scheme) <= 0 || parsedUrl.Scheme == "http" || parsedUrl.Scheme == "https" + } else if useHttp { + _, err := url.Parse(fmt.Sprint("http://", host, ":", port)) + if err != nil { + fmt.Fprintln(os.Stderr, "Error parsing URL: ", err) + flag.Usage() + } + } + + cmd := flag.Arg(0) + var err error + if useHttp { + trans, err = thrift.NewTHttpClient(parsedUrl.String()) + if len(headers) > 0 { + httptrans := trans.(*thrift.THttpClient) + for key, value := range headers { + httptrans.SetHeader(key, value) + } + } + } else { + portStr := fmt.Sprint(port) + if strings.Contains(host, ":") { + host, portStr, err = net.SplitHostPort(host) + if err != nil { + fmt.Fprintln(os.Stderr, "error with host:", err) + os.Exit(1) + } + } + trans, err = thrift.NewTSocket(net.JoinHostPort(host, portStr)) + if err != nil { + fmt.Fprintln(os.Stderr, "error resolving address:", err) + os.Exit(1) + } + if framed { + trans = thrift.NewTFramedTransport(trans) + } + } + if err != nil { + fmt.Fprintln(os.Stderr, "Error creating transport", err) + os.Exit(1) + } + defer trans.Close() + var protocolFactory thrift.TProtocolFactory + switch protocol { + case "compact": + protocolFactory = thrift.NewTCompactProtocolFactory() + break + case "simplejson": + protocolFactory = thrift.NewTSimpleJSONProtocolFactory() + break + case "json": + protocolFactory = thrift.NewTJSONProtocolFactory() + break + case "binary", "": + protocolFactory = thrift.NewTBinaryProtocolFactoryDefault() + break + default: + fmt.Fprintln(os.Stderr, "Invalid protocol specified: ", protocol) + Usage() + os.Exit(1) + } + iprot := protocolFactory.GetProtocol(trans) + oprot := protocolFactory.GetProtocol(trans) + client := proxy.NewProxyServiceClient(thrift.NewTStandardClient(iprot, oprot)) + if err := trans.Open(); err != nil { + fmt.Fprintln(os.Stderr, "Error opening socket to ", host, ":", port, " ", err) + os.Exit(1) + } + + switch cmd { + case "getAllFlows": + if flag.NArg() - 1 != 0 { + fmt.Fprintln(os.Stderr, "GetAllFlows requires 0 args") + flag.Usage() + } + fmt.Print(client.GetAllFlows(context.Background())) + fmt.Print("\n") + break + case "getFlowById": + if flag.NArg() - 1 != 1 { + fmt.Fprintln(os.Stderr, "GetFlowById requires 1 args") + flag.Usage() + } + argvalue0, err7 := (strconv.ParseInt(flag.Arg(1), 10, 64)) + if err7 != nil { + Usage() + return + } + value0 := argvalue0 + fmt.Print(client.GetFlowById(context.Background(), value0)) + fmt.Print("\n") + break + case "": + Usage() + break + default: + fmt.Fprintln(os.Stderr, "Invalid function ", cmd) + } +} diff --git a/traffic_updater/go/osrm_traffic_updater/osrm_traffic_updater.go b/traffic_updater/go/osrm_traffic_updater/osrm_traffic_updater.go new file mode 100644 index 000000000..f6853b1f3 --- /dev/null +++ b/traffic_updater/go/osrm_traffic_updater/osrm_traffic_updater.go @@ -0,0 +1,127 @@ +package main + +import ( + "bufio" + "context" + "flag" + "fmt" + "os" + "strconv" + "time" + + "github.com/Telenav/osrm-backend/traffic_updater/go/gen-go/proxy" + "github.com/apache/thrift/lib/go/thrift" +) + +var flags struct { + port int + ip string + csvFile string + highPrecision bool +} + +func init() { + flag.IntVar(&flags.port, "p", 6666, "traffic proxy listening port") + flag.StringVar(&flags.ip, "c", "127.0.0.1", "traffic proxy ip address") + flag.StringVar(&flags.csvFile, "f", "traffic.csv", "OSRM traffic csv file") + flag.BoolVar(&flags.highPrecision, "d", true, "use high precision speeds, i.e. decimal") +} + +func dumpFlowsToCsv(csvFile string, flows []*proxy.Flow) { + + if _, err := os.Stat(csvFile); err == nil { + // csvFile exists, remove it + rmErr := os.Remove(csvFile) + if rmErr != nil { + fmt.Println(rmErr) + return + } + } + + f, err := os.OpenFile(csvFile, os.O_RDWR|os.O_CREATE, 0755) + if err != nil { + fmt.Println(err) + return + } + defer f.Close() + writer := bufio.NewWriter(f) + + for i, flow := range flows { + var osrmTrafficLine string + if flags.highPrecision { + osrmTrafficLine = fmt.Sprintf("%d,%d,%f\n", flow.FromId, flow.ToId, flow.Speed) + } else { + osrmTrafficLine = fmt.Sprintf("%d,%d,%d\n", flow.FromId, flow.ToId, int(flow.Speed)) + } + + // print first 10 lines for debug + if i < 10 { + fmt.Printf("[ %d ] %v\n", i, flow) + fmt.Printf("[ %d ] %s\n", i, osrmTrafficLine) + } + + // write to csv + _, err := writer.WriteString(osrmTrafficLine) + if err != nil { + fmt.Println(err) + return + } + } + writer.Flush() + f.Sync() + fmt.Printf("total wrote to %s count: %d\n", csvFile, len(flows)) +} + +func main() { + flag.Parse() + + var transport thrift.TTransport + var err error + + // make socket + targetServer := flags.ip + ":" + strconv.Itoa(flags.port) + fmt.Println("connect traffic proxy " + targetServer) + transport, err = thrift.NewTSocket(targetServer) + if err != nil { + fmt.Println("Error opening socket:", err) + return + } + + // Buffering + transport, err = thrift.NewTFramedTransportFactoryMaxLength(thrift.NewTTransportFactory(), 1024*1024*1024).GetTransport(transport) + if err != nil { + fmt.Println("Error get transport:", err) + return + } + defer transport.Close() + if err := transport.Open(); err != nil { + fmt.Println("Error opening transport:", err) + return + } + + // protocol encoder&decoder + protocol := thrift.NewTCompactProtocolFactory().GetProtocol(transport) + + // create proxy client + client := proxy.NewProxyServiceClient(thrift.NewTStandardClient(protocol, protocol)) + + // get flows + startTime := time.Now() + fmt.Println("getting flows") + var defaultCtx = context.Background() + flows, err := client.GetAllFlows(defaultCtx) + if err != nil { + fmt.Println("get flows failed:", err) + return + } + fmt.Printf("got flows count: %d\n", len(flows)) + afterGotFlowTime := time.Now() + fmt.Printf("get flows time used: %f seconds\n", afterGotFlowTime.Sub(startTime).Seconds()) + + // dump to csv + fmt.Println("dump flows to: " + flags.csvFile) + dumpFlowsToCsv(flags.csvFile, flows) + endTime := time.Now() + fmt.Printf("dump csv time used: %f seconds\n", endTime.Sub(afterGotFlowTime).Seconds()) + +} diff --git a/traffic_updater/proxy.thrift b/traffic_updater/proxy.thrift new file mode 100644 index 000000000..6bc259f2c --- /dev/null +++ b/traffic_updater/proxy.thrift @@ -0,0 +1,13 @@ + +struct Flow { + 1: required i64 fromId; + 2: required i64 toId; + 3: required i64 wayId; + 4: required double speed; + 5: required i32 trafficLevel; +} + +service ProxyService { + list getAllFlows() + Flow getFlowById(1:i64 wayId) +}