-
Notifications
You must be signed in to change notification settings - Fork 0
/
ttss.go
115 lines (103 loc) · 2.72 KB
/
ttss.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
package krkstops
import (
"context"
"errors"
"log/slog"
"slices"
"sync"
"time"
"github.com/PiotrKozimor/krkstops/pb"
"github.com/PiotrKozimor/krkstops/pkg/search"
"github.com/PiotrKozimor/krkstops/pkg/ttss"
)
type typedDeparture struct {
ttss.Departure
transit pb.Transit
}
type typedClient struct {
ttssClient
transit pb.Transit
}
func (s *KrkStopsServer) GetDepartures2(ctx context.Context, req *pb.GetDepartures2Request) (*pb.GetDepartures2Response, error) {
cachedDeps, cachedAt, ok := s.depsCache.get(uint(req.Id))
if !ok {
stop := s.searchCli.Get(uint(req.Id))
cachedDeps = make([]typedDeparture, 0, 20)
errs := make([]error, 0)
m := sync.Mutex{}
wg := sync.WaitGroup{}
getDepartures := func(cli ttssClient, transit pb.Transit) {
deps, err := cli.GetDepartures(stop.Id)
m.Lock()
if err != nil {
errs = append(errs, err)
} else {
for _, dep := range deps {
cachedDeps = append(cachedDeps, typedDeparture{
Departure: dep,
transit: transit,
})
}
}
m.Unlock()
wg.Done()
}
if stop.Bus {
wg.Add(1)
go getDepartures(s.ttssBusCli, pb.Transit_BUS)
}
if stop.Tram {
wg.Add(1)
go getDepartures(s.ttssTramCli, pb.Transit_TRAM)
}
wg.Wait()
err := errors.Join(errs...)
if err != nil {
if len(cachedDeps) == 0 {
return nil, err
} else {
slog.ErrorContext(ctx, "get departures", "error", err)
}
}
slices.SortFunc(cachedDeps, func(a, b typedDeparture) int {
return int(a.RelativeTime - b.RelativeTime)
})
s.depsCache.set(stop.Id, cachedDeps)
}
return &pb.GetDepartures2Response{
Departures: protoDepartures(cachedDeps, cachedAt),
}, nil
}
func (s *KrkStopsServer) SearchStops2(ctx context.Context, req *pb.SearchStops2Request) (*pb.SearchStops2Response, error) {
stops := s.searchCli.Search(req.Query, 10)
return &pb.SearchStops2Response{
Stops: protoStops(stops),
}, nil
}
func protoStops(stops []search.Stop) []*pb.Stop {
pStops := make([]*pb.Stop, len(stops))
for i := range stops {
pStops[i] = &pb.Stop{
Name: stops[i].Name,
Id: uint32(stops[i].Id),
}
}
return pStops
}
func protoDepartures(departures []typedDeparture, cachedAt *time.Time) []*pb.Departure {
pDepartures := make([]*pb.Departure, len(departures))
for i := range departures {
pDepartures[i] = &pb.Departure{
RelativeTime: departures[i].Departure.RelativeTime,
PlannedTime: departures[i].Departure.PlannedTime,
PatternText: departures[i].Departure.PatternText,
Direction: departures[i].Departure.Direction,
Type: departures[i].transit,
Predicted: departures[i].Departure.Predicted,
}
if cachedAt != nil {
pDepartures[i].RelativeTime -= int32(time.Now().Sub(*cachedAt).Seconds())
}
}
return pDepartures
}