From e546034c26df6fe5fb7ee50e78caec9d9c49f111 Mon Sep 17 00:00:00 2001 From: Bel LaPointe Date: Tue, 11 Jan 2022 22:54:18 -0500 Subject: [PATCH] multi-client but one ntg search, nontrivial config.json change --- broker/broker.go | 8 +++++++- broker/job.go | 38 +++++++++++++++++++++++++---------- config.json | 26 ++++++++++++++++-------- config/config.go | 25 +++++++++++++++++++---- main.go | 50 ++++++++++++++++++++++++++++------------------ message/matrix.go | 31 +++++++++++++++++++++------- message/message.go | 7 ++++++- todo.yaml | 7 ++++--- 8 files changed, 138 insertions(+), 54 deletions(-) diff --git a/broker/broker.go b/broker/broker.go index 8657464..6e11b1c 100644 --- a/broker/broker.go +++ b/broker/broker.go @@ -1,6 +1,12 @@ package broker -import "local/truckstop/config" +import ( + "local/truckstop/config" + + "golang.org/x/time/rate" +) + +var limiter = rate.NewLimiter(rate.Limit(0.3), 1) type Broker interface { Search([]config.State) ([]Job, error) diff --git a/broker/job.go b/broker/job.go index 8666a37..fe929e2 100644 --- a/broker/job.go +++ b/broker/job.go @@ -3,6 +3,8 @@ package broker import ( "fmt" "local/truckstop/config" + "log" + "strings" "time" ) @@ -37,15 +39,29 @@ func (j JobLocation) String() string { } func (j Job) FormatMultilineText() string { - return fmt.Sprintf( - "--- %s: %s => %s ---\nPickup: %s\nDropoff: %s\nNotes: %d lbs, %d miles, %s", - config.Get().Name, - j.Pickup.State, - j.Dropoff.State, - j.Pickup.String(), - j.Dropoff.String(), - j.Weight, - j.Miles, - j.Meta, - ) + foo := func(client string) string { + return fmt.Sprintf( + "--- %s: %s => %s ---\nPickup: %s\nDropoff: %s\nNotes: %d lbs, %d miles, %s", + client, + j.Pickup.State, + j.Dropoff.State, + j.Pickup.String(), + j.Dropoff.String(), + j.Weight, + j.Miles, + j.Meta, + ) + } + out := "" + clients := config.Get().Clients + for k := range clients { + log.Printf("job multiline: %+v contains %s then use %v", clients[k].States, j.Pickup.State, k) + if strings.Contains(fmt.Sprint(clients[k].States), j.Pickup.State) { + if len(out) > 0 { + out += "\n\n" + } + out += foo(k) + } + } + return out } diff --git a/config.json b/config.json index bb8526a..443cc21 100644 --- a/config.json +++ b/config.json @@ -1,23 +1,33 @@ { - "Name": "pa", "Interval": { "Input": "10s..30s", "OK": "6h0m0s..6h0m0s", "Error": "6h0m0s..6h0m0s" }, - "States": [ - "FL", - "GA", - "NC" - ], + "Clients": { + "pa": { + "States": [ + "OH" + ], + "IDs": { + "Matrix": "@belandbroc:matrix.org" + } + }, + "caleb": { + "States": [ + "OH" + ], + "IDs": { + "Matrix": "@belandbroc:matrix.org" + } + } + }, "Storage": [ "map" ], - "Client": "breellocaldev@gmail.com", "Message": { "Matrix": { "ReceiveEnabled": true, - "Client": "@belandbroc:matrix.org", "Mock": true, "Homeserver": "https://matrix-client.matrix.org", "Username": "@breellocaldev:matrix.org", diff --git a/config/config.go b/config/config.go index 09c6c12..4571203 100644 --- a/config/config.go +++ b/config/config.go @@ -9,19 +9,21 @@ import ( ) type Config struct { - Name string Interval struct { Input Duration OK Duration Error Duration } - States []State + Clients map[string]struct { + States []State + IDs struct { + Matrix string + } + } Storage []string - Client string Message struct { Matrix struct { ReceiveEnabled bool - Client string Mock bool Homeserver string Username string @@ -54,6 +56,21 @@ func configPath() string { return p } +func AllStates() []State { + c := Get() + statem := map[State]struct{}{} + for _, v := range c.Clients { + for _, state := range v.States { + statem[state] = struct{}{} + } + } + states := make([]State, 0, len(statem)+1) + for k := range statem { + states = append(states, k) + } + return states +} + func Refresh() error { b, err := ioutil.ReadFile(configPath()) if err != nil { diff --git a/main.go b/main.go index e6e16fa..3861118 100644 --- a/main.go +++ b/main.go @@ -49,39 +49,51 @@ func matrixrecv() error { if err != nil { return err } - states := map[config.State]struct{}{} + states := map[string]map[config.State]struct{}{} for _, msg := range messages { - if len(states) > 0 { + if _, ok := states[msg.Sender]; ok { continue } - for _, state := range parseOutStates([]byte(msg)) { - states[state] = struct{}{} + states[msg.Sender] = map[config.State]struct{}{} + for _, state := range parseOutStates([]byte(msg.Content)) { + states[msg.Sender][state] = struct{}{} } } setNewStates(states) return nil } -func setNewStates(states map[config.State]struct{}) { +func setNewStates(states map[string]map[config.State]struct{}) { if len(states) == 0 { return } - newstates := []config.State{} - for k := range states { - newstates = append(newstates, k) - } - sort.Slice(newstates, func(i, j int) bool { - return newstates[i] < newstates[j] - }) conf := *config.Get() - if fmt.Sprint(newstates) == fmt.Sprint(conf.States) { + changed := map[string][]config.State{} + for client, clientStates := range states { + newstates := []config.State{} + for k := range clientStates { + newstates = append(newstates, k) + } + sort.Slice(newstates, func(i, j int) bool { + return newstates[i] < newstates[j] + }) + clientconf := conf.Clients[client] + if fmt.Sprint(newstates) == fmt.Sprint(clientconf.States) { + continue + } + clientconf.States = newstates + conf.Clients[client] = clientconf + changed[client] = newstates + } + if len(changed) == 0 { return } - conf.States = newstates log.Printf("updating config new states: %+v", conf) config.Set(conf) - if err := sendNewStates(conf.States); err != nil { - log.Printf("failed to send new states %+v: %v", conf.States, err) + for client, states := range changed { + if err := sendNewStates(client, states); err != nil { + log.Printf("failed to send new states %s/%+v: %v", client, states, err) + } } } @@ -160,7 +172,7 @@ func once() error { } func getJobs() ([]broker.Job, error) { - states := config.Get().States + states := config.AllStates() ntg := broker.NewNTGVision() if config.Get().Brokers.NTG.Mock { ntg = ntg.WithMock() @@ -200,7 +212,7 @@ func sendJob(job broker.Job) error { return sender.Send(job.FormatMultilineText()) } -func sendNewStates(states []config.State) error { +func sendNewStates(client string, states []config.State) error { sender := message.NewMatrix() - return sender.Send(fmt.Sprintf("now searching for loads from: %+v", states)) + return sender.Send(fmt.Sprintf("%s: now searching for loads from: %+v", client, states)) } diff --git a/message/matrix.go b/message/matrix.go index c3cac14..b618b00 100644 --- a/message/matrix.go +++ b/message/matrix.go @@ -13,7 +13,6 @@ type Matrix struct { username string token string room string - client string } func NewMatrix() Matrix { @@ -24,7 +23,6 @@ func NewMatrix() Matrix { token: conf.Token, room: conf.Room, mock: conf.Mock, - client: conf.Client, } } @@ -32,32 +30,51 @@ func (m Matrix) getclient() (*gomatrix.Client, error) { return gomatrix.NewClient(m.homeserver, m.username, m.token) } -func (m Matrix) Receive() ([]string, error) { +func (m Matrix) Receive() ([]Message, error) { if m.mock { log.Printf("matrix.Receive()") - return []string{"FL, GA, NC"}, nil + messages := make([]Message, 0) + for k := range config.Get().Clients { + messages = append(messages, Message{Sender: k, Content: "OH"}) + } + return messages, nil + } + clients := config.Get().Clients + matrixIDs := map[string]struct{}{} + for k := range clients { + matrixIDs[clients[k].IDs.Matrix] = struct{}{} + } + if len(matrixIDs) == 0 { + return nil, nil } c, err := m.getclient() if err != nil { return nil, err } - messages := make([]string, 0) + messages := make([]Message, 0) result, err := c.Messages(m.room, "", "", 'b', 50) for _, event := range result.Chunk { - if event.Sender != m.client { + if _, ok := matrixIDs[event.Sender]; !ok { continue } switch event.Type { case "m.room.message": b, ok := event.Body() if ok { - messages = append(messages, b) + messages = append(messages, Message{Sender: event.Sender, Content: b}) } } } if err != nil { return nil, err } + for i := range messages { + for k, v := range config.Get().Clients { + if v.IDs.Matrix == messages[i].Sender { + messages[i].Sender = k + } + } + } return messages, nil } diff --git a/message/message.go b/message/message.go index 06c9d44..eea2306 100644 --- a/message/message.go +++ b/message/message.go @@ -2,5 +2,10 @@ package message type Sender interface { Send(string) error - Receive() ([]string, error) + Receive() ([]Message, error) +} + +type Message struct { + Sender string + Content string } diff --git a/todo.yaml b/todo.yaml index 96526a9..642e1a7 100644 --- a/todo.yaml +++ b/todo.yaml @@ -1,8 +1,7 @@ todo: -- modify old items once no longer available -- many users -> 1 ntg query - accept after date -- "caleb: my-usual-stuff" to alias +- modify old items once no longer available; drop stale jobs good candidate but requires new matrix interaction +- "caleb: commands: args" - rate LIMIT - more than NTG - accept pause commands @@ -16,6 +15,8 @@ todo: - accept states via element for one system - set up copy for caleb, broc done: +- many users -> 1 ntg query +- multi client - rm email - send matrix msg on config change - setup pa on element