Skip to content

Commit 7471a59

Browse files
committed
feat(#3): implementing an auto reply after silence feature
1 parent 7b37fbe commit 7471a59

File tree

3 files changed

+86
-10
lines changed

3 files changed

+86
-10
lines changed

.gitignore

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,9 @@ go.work.sum
2727
# env file
2828
.env
2929

30+
# Rules file
31+
rules.yaml
32+
3033
# Editor/IDE
3134
# .idea/
3235
# .vscode/

main.go

Lines changed: 72 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -31,12 +31,13 @@ type Rules struct {
3131
}
3232

3333
type Rule struct {
34-
Name string `yaml:"name"`
35-
Type string `yaml:"type"` // "redirect" or "auto_reply"
36-
FromSender string `yaml:"from_sender"`
37-
ToReceivers []string `yaml:"to_receivers,omitempty"`
38-
ReplyText string `yaml:"reply_text,omitempty"`
39-
Enabled bool `yaml:"enabled"`
34+
Name string `yaml:"name"`
35+
Type string `yaml:"type"` // "redirect", "auto_reply", or "auto_reply_after_silence"
36+
FromSender string `yaml:"from_sender"`
37+
ToReceivers []string `yaml:"to_receivers,omitempty"`
38+
ReplyText string `yaml:"reply_text,omitempty"`
39+
SilenceDurationSecs int `yaml:"silence_duration_secs,omitempty"` // Time in seconds before auto-reply triggers
40+
Enabled bool `yaml:"enabled"`
4041
}
4142

4243
// WebSocket message structures
@@ -75,14 +76,20 @@ type OutgoingMessage struct {
7576
}
7677

7778
var (
78-
conn *websocket.Conn
79-
config Config
80-
rules Rules
79+
conn *websocket.Conn
80+
config Config
81+
rules Rules
82+
lastConversationMap map[string]time.Time // Tracks last message time per sender
83+
autoReplyStatusMap map[string]bool // Tracks if auto-reply was already sent
8184
)
8285

8386
func main() {
8487
log.Println("iOSMB-Router starting...")
8588

89+
// Initialize tracking maps
90+
lastConversationMap = make(map[string]time.Time)
91+
autoReplyStatusMap = make(map[string]bool)
92+
8693
// Load configuration from environment or config file
8794
loadConfig()
8895

@@ -201,9 +208,21 @@ func processMessage(data interface{}) {
201208

202209
msg := msgData.Message[0]
203210

211+
// Get sender identifier (prefer ChatID, fallback to Author)
212+
senderID := msg.ChatID
213+
if senderID == "" {
214+
senderID = msg.Author
215+
}
216+
217+
// Update last conversation time for this sender
218+
currentTime := time.Now()
219+
lastConversationMap[senderID] = currentTime
220+
204221
// Skip messages sent by you (sender == 1)
205222
if msg.Sender == 1 {
206223
log.Printf("Skipping own message")
224+
// Reset auto-reply status when you send a message (conversation resumed)
225+
autoReplyStatusMap[senderID] = false
207226
return
208227
}
209228

@@ -231,6 +250,8 @@ func processMessage(data interface{}) {
231250
handleRedirect(msg, rule)
232251
case "auto_reply":
233252
handleAutoReply(msg, rule)
253+
case "auto_reply_after_silence":
254+
handleAutoReplyAfterSilence(msg, rule, senderID)
234255
default:
235256
log.Printf("Unknown rule type: %s", rule.Type)
236257
}
@@ -272,6 +293,48 @@ func handleAutoReply(msg MessageInfo, rule Rule) {
272293
sendMessage(outMsg)
273294
}
274295

296+
func handleAutoReplyAfterSilence(msg MessageInfo, rule Rule, senderID string) {
297+
// Check if auto-reply was already sent during this silence period
298+
if autoReplyStatusMap[senderID] {
299+
log.Printf("Auto-reply already sent to %s during this silence period", msg.Author)
300+
return
301+
}
302+
303+
// Get last conversation time
304+
lastTime, exists := lastConversationMap[senderID]
305+
if !exists {
306+
// First message from this sender, don't auto-reply yet
307+
log.Printf("First message from %s, tracking conversation time", msg.Author)
308+
return
309+
}
310+
311+
// Calculate time since last conversation
312+
timeSinceLastMsg := time.Since(lastTime)
313+
requiredSilence := time.Duration(rule.SilenceDurationSecs) * time.Second
314+
315+
log.Printf("Time since last message from %s: %v (required: %v)",
316+
msg.Author, timeSinceLastMsg, requiredSilence)
317+
318+
// Check if enough time has passed
319+
if timeSinceLastMsg >= requiredSilence {
320+
log.Printf("Auto-replying to %s after %v of silence", msg.Author, timeSinceLastMsg)
321+
322+
outMsg := OutgoingMessage{
323+
Address: msg.ChatID,
324+
Text: rule.ReplyText,
325+
Subject: "",
326+
Attachments: []interface{}{},
327+
}
328+
329+
sendMessage(outMsg)
330+
331+
// Mark that auto-reply was sent for this silence period
332+
autoReplyStatusMap[senderID] = true
333+
} else {
334+
log.Printf("Not enough silence time for %s, skipping auto-reply", msg.Author)
335+
}
336+
}
337+
275338
func sendMessage(msg OutgoingMessage) {
276339
// Use HTTP POST like the web client does
277340
protocol := "http"

rules.example.yaml

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,9 +11,19 @@ rules:
1111
- "+33755442211"
1212
enabled: true
1313

14-
# Example: Auto-reply to a specific sender
14+
# Example: Auto-reply to a specific sender (immediate reply)
1515
- name: "Auto reply example"
1616
type: auto_reply
1717
from_sender: "+33233556699"
1818
reply_text: "I will answer you shortly"
1919
enabled: true
20+
21+
# Example: Auto-reply after silence period (e.g., 1 hour)
22+
# This will only reply if there hasn't been any conversation with the sender
23+
# for the specified duration. The reply is sent only once per silence period.
24+
- name: "Auto reply after 1 hour of silence"
25+
type: auto_reply_after_silence
26+
from_sender: "+33611223344"
27+
reply_text: "I will reply you soon"
28+
silence_duration_secs: 3600 # 1 hour = 3600 seconds (1h), 7200 = 2h, 1800 = 30mins
29+
enabled: true

0 commit comments

Comments
 (0)