| 119 | } |
| 120 | |
| 121 | func (b *Botshed) loadCanned() { |
| 122 | if b.Upstream == "" { |
| 123 | b.logger.Warn("botshed: upstream empty, canned responses disabled") |
| 124 | return |
| 125 | } |
| 126 | client := &http.Client{Timeout: 10 * time.Second} |
| 127 | results := make([][]byte, 0, len(seedCmds)) |
| 128 | deadline := time.Now().Add(30 * time.Second) |
| 129 | delay := 500 * time.Millisecond |
| 130 | |
| 131 | for _, cmd := range seedCmds { |
| 132 | var body []byte |
| 133 | for { |
| 134 | b2, err := fetchOne(client, b.Upstream, cmd) |
| 135 | if err == nil { |
| 136 | body = b2 |
| 137 | break |
| 138 | } |
| 139 | if time.Now().After(deadline) { |
| 140 | b.logger.Error("botshed: canned fetch failed, deadline reached", |
| 141 | zap.String("cmd", cmd), zap.Error(err)) |
| 142 | break |
| 143 | } |
| 144 | time.Sleep(delay) |
| 145 | if delay < 4*time.Second { |
| 146 | delay *= 2 |
| 147 | } |
| 148 | } |
| 149 | if body != nil { |
| 150 | results = append(results, body) |
| 151 | } |
| 152 | } |
| 153 | if len(results) == 0 { |
| 154 | b.logger.Error("botshed: no canned responses loaded") |
| 155 | return |
| 156 | } |
| 157 | b.canned.Store(&results) |
| 158 | b.logger.Info("botshed: loaded canned responses", zap.Int("count", len(results))) |
| 159 | } |
| 160 | |
| 161 | func fetchOne(c *http.Client, upstream, cmd string) ([]byte, error) { |
| 162 | u := fmt.Sprintf("http://%s/explain?cmd=%s", upstream, url.QueryEscape(cmd)) |