mods: Add reminder module
This commit is contained in:
parent
3977a5de53
commit
07ac1880ee
2 changed files with 185 additions and 4 deletions
14
mods/main.go
14
mods/main.go
|
@ -52,6 +52,10 @@ var mods = map[string]Mod{
|
||||||
OnInit: initstt,
|
OnInit: initstt,
|
||||||
OnMessage: stt,
|
OnMessage: stt,
|
||||||
},
|
},
|
||||||
|
"remind": {
|
||||||
|
OnInit: initremind,
|
||||||
|
OnMessage: remind,
|
||||||
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
func initmods() {
|
func initmods() {
|
||||||
|
@ -102,6 +106,7 @@ func main() {
|
||||||
gillmt = flag.String("gillmt", "gill.ttf", "Path to gill.ttf (Gill Sans MT font)")
|
gillmt = flag.String("gillmt", "gill.ttf", "Path to gill.ttf (Gill Sans MT font)")
|
||||||
sourcesans = flag.String("sourcesans", "source.ttf", "Path to source.ttf (Source Sans Pro font)")
|
sourcesans = flag.String("sourcesans", "source.ttf", "Path to source.ttf (Source Sans Pro font)")
|
||||||
macropath = flag.String("macropath", "macros.json", "Path to macros db (JSON)")
|
macropath = flag.String("macropath", "macros.json", "Path to macros db (JSON)")
|
||||||
|
remindpath = flag.String("remindpath", "reminders.json", "Path to reminder db (JSON)")
|
||||||
proverbi = flag.String("proverbi", "proverbi.txt", "Path to proverbi pairs (separated by /)")
|
proverbi = flag.String("proverbi", "proverbi.txt", "Path to proverbi pairs (separated by /)")
|
||||||
wittoken = flag.String("wit", "", "Wit.ai token")
|
wittoken = flag.String("wit", "", "Wit.ai token")
|
||||||
gapifile = flag.String("gapi", "gapi.json", "Google API Service Credentials file")
|
gapifile = flag.String("gapi", "gapi.json", "Google API Service Credentials file")
|
||||||
|
@ -127,10 +132,11 @@ func main() {
|
||||||
initmods()
|
initmods()
|
||||||
|
|
||||||
var err error
|
var err error
|
||||||
broker, err = tg.CreateBrokerClient(*brokerAddr, dispatch)
|
broker, err = tg.ConnectToBroker(*brokerAddr)
|
||||||
if err != nil {
|
assert(err)
|
||||||
panic(err)
|
defer broker.Close()
|
||||||
}
|
|
||||||
|
assert(tg.RunBrokerClient(broker, dispatch))
|
||||||
}
|
}
|
||||||
|
|
||||||
func assert(err error) {
|
func assert(err error) {
|
||||||
|
|
175
mods/remind.go
Normal file
175
mods/remind.go
Normal file
|
@ -0,0 +1,175 @@
|
||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"encoding/json"
|
||||||
|
"fmt"
|
||||||
|
"log"
|
||||||
|
"os"
|
||||||
|
"strconv"
|
||||||
|
"strings"
|
||||||
|
"time"
|
||||||
|
"unicode"
|
||||||
|
|
||||||
|
"github.com/hamcha/clessy/tg"
|
||||||
|
)
|
||||||
|
|
||||||
|
var remindpath *string
|
||||||
|
|
||||||
|
type Reminder struct {
|
||||||
|
TargetID int64
|
||||||
|
When int64
|
||||||
|
Text string
|
||||||
|
}
|
||||||
|
|
||||||
|
var reminders map[string]Reminder
|
||||||
|
|
||||||
|
const ReminderMaxDuration = time.Hour * 24 * 30 * 3
|
||||||
|
|
||||||
|
func initremind() {
|
||||||
|
reminders = make(map[string]Reminder)
|
||||||
|
file, err := os.Open(*remindpath)
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
defer file.Close()
|
||||||
|
err = json.NewDecoder(file).Decode(&reminders)
|
||||||
|
if err != nil {
|
||||||
|
log.Println("[remind] WARN: Could not load pending reminders (malformed or unreadable file): " + err.Error())
|
||||||
|
return
|
||||||
|
}
|
||||||
|
for id, _ := range reminders {
|
||||||
|
go runreminder(id)
|
||||||
|
}
|
||||||
|
log.Printf("[remind] Loaded %d pending reminders from %s\n", len(reminders), *remindpath)
|
||||||
|
}
|
||||||
|
|
||||||
|
func remind(broker *tg.Broker, update tg.APIMessage) {
|
||||||
|
if isCommand(update, "ricordami") {
|
||||||
|
// Supported formats:
|
||||||
|
// Xs/m/h/d => in X seconds/minutes/hours/days
|
||||||
|
// HH:MM => at HH:MM (24 hour format)
|
||||||
|
// HH:MM:SS => at HH:MM:SS (24 hour format)
|
||||||
|
// dd/mm/yyyy => same hour, specific date
|
||||||
|
// dd/mm/yyyy-HH:MM => specific hour, specific dat
|
||||||
|
// dd/mm/yyyy-HH:MM:SS => specific hour, specific date
|
||||||
|
|
||||||
|
parts := strings.SplitN(*(update.Text), " ", 3)
|
||||||
|
if len(parts) < 3 {
|
||||||
|
broker.SendTextMessage(update.Chat, "<b>Sintassi</b>\n/ricordami <i>[quando]</i> Messaggio\n\n<b>Formati supportati per [quando]</b>:\n 10s 10m 10h 10d (secondi/minuti/ore/giorni)\n 13:20 15:55:01 (ora dello stesso giorno, formato 24h)\n 11/02/2099 11/02/2099-11:20:01 (giorno diverso, stessa ora [1] o specifica [2])", &update.MessageID)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
format := parts[1]
|
||||||
|
message := parts[2]
|
||||||
|
|
||||||
|
timestamp, err := parseDuration(format)
|
||||||
|
if err != nil {
|
||||||
|
broker.SendTextMessage(update.Chat, err.Error(), &update.MessageID)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
id := strconv.FormatInt(update.Chat.ChatID, 36) + "-" + strconv.FormatInt(update.MessageID, 36)
|
||||||
|
reminders[id] = Reminder{
|
||||||
|
TargetID: update.User.UserID,
|
||||||
|
When: timestamp.Unix(),
|
||||||
|
Text: message,
|
||||||
|
}
|
||||||
|
savereminder()
|
||||||
|
go runreminder(id)
|
||||||
|
|
||||||
|
whenday := "più tardi"
|
||||||
|
_, todaym, todayd := time.Now().Date()
|
||||||
|
_, targetm, targetd := timestamp.Date()
|
||||||
|
if todaym != targetm || todayd != targetd {
|
||||||
|
whenday = "il " + timestamp.Format("2/1")
|
||||||
|
}
|
||||||
|
whentime := "alle " + timestamp.Format("15:04:05")
|
||||||
|
broker.SendTextMessage(update.Chat, "Ok, vedrò di avvisarti "+whenday+" "+whentime, &update.MessageID)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func runreminder(id string) {
|
||||||
|
// Get reminder
|
||||||
|
r := reminders[id]
|
||||||
|
remaining := r.When - time.Now().Unix()
|
||||||
|
if remaining > 0 {
|
||||||
|
// Wait remaining time
|
||||||
|
time.Sleep(time.Second * time.Duration(remaining))
|
||||||
|
}
|
||||||
|
// Remind!
|
||||||
|
broker.SendTextMessage(&tg.APIChat{ChatID: r.TargetID}, "<b>Heyla! Mi avevi chiesto di ricordarti questo:</b>\n"+r.Text, nil)
|
||||||
|
// Delete reminder from pending list and save list to disk
|
||||||
|
delete(reminders, id)
|
||||||
|
savereminder()
|
||||||
|
}
|
||||||
|
|
||||||
|
func savereminder() {
|
||||||
|
file, err := os.Create(*remindpath)
|
||||||
|
if err != nil {
|
||||||
|
log.Println("[remind] WARN: Could not open pending reminders file: " + err.Error())
|
||||||
|
return
|
||||||
|
}
|
||||||
|
err = json.NewEncoder(file).Encode(reminders)
|
||||||
|
if err != nil {
|
||||||
|
log.Println("[macro] WARN: Could not save pending reminders into file: " + err.Error())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func isSscanfValid(n int, err error) bool {
|
||||||
|
return err == nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func parseDuration(date string) (time.Time, error) {
|
||||||
|
now := time.Now()
|
||||||
|
num := 0
|
||||||
|
sep := ' '
|
||||||
|
hour := now.Hour()
|
||||||
|
min := now.Minute()
|
||||||
|
sec := now.Second()
|
||||||
|
day := now.Day()
|
||||||
|
month := now.Month()
|
||||||
|
year := now.Year()
|
||||||
|
switch {
|
||||||
|
case isSscanfValid(fmt.Sscanf(date, "%d/%d/%d-%d:%d:%d", &day, &month, &year, &hour, &min, &sec)):
|
||||||
|
case isSscanfValid(fmt.Sscanf(date, "%d/%d/%d-%d:%d", &day, &month, &year, &hour, &min)):
|
||||||
|
sec = now.Second()
|
||||||
|
case isSscanfValid(fmt.Sscanf(date, "%d/%d/%d", &day, &month, &year)):
|
||||||
|
hour = now.Hour()
|
||||||
|
min = now.Minute()
|
||||||
|
sec = now.Second()
|
||||||
|
case isSscanfValid(fmt.Sscanf(date, "%d:%d:%d", &hour, &min, &sec)):
|
||||||
|
day = now.Day()
|
||||||
|
month = now.Month()
|
||||||
|
year = now.Year()
|
||||||
|
case isSscanfValid(fmt.Sscanf(date, "%d:%d", &hour, &min)):
|
||||||
|
day = now.Day()
|
||||||
|
month = now.Month()
|
||||||
|
year = now.Year()
|
||||||
|
sec = now.Second()
|
||||||
|
case isSscanfValid(fmt.Sscanf(date, "%d%c", &num, &sep)):
|
||||||
|
dur := time.Duration(num)
|
||||||
|
switch unicode.ToLower(sep) {
|
||||||
|
case 's':
|
||||||
|
dur *= time.Second
|
||||||
|
case 'm':
|
||||||
|
dur *= time.Minute
|
||||||
|
case 'h':
|
||||||
|
dur *= time.Hour
|
||||||
|
case 'd':
|
||||||
|
dur *= time.Hour * 24
|
||||||
|
default:
|
||||||
|
return now, fmt.Errorf("La durata ha una unità che non conosco, usa una di queste: s (secondi) m (minuti) h (ore) d (giorni)")
|
||||||
|
}
|
||||||
|
return now.Add(dur), nil
|
||||||
|
default:
|
||||||
|
return now, fmt.Errorf("Non capisco quando dovrei ricordartelo!")
|
||||||
|
}
|
||||||
|
targetDate := time.Date(year, month, day, hour, min, sec, 0, now.Location())
|
||||||
|
if targetDate.Before(now) {
|
||||||
|
return now, fmt.Errorf("Non posso ricordarti cose nel passato!")
|
||||||
|
}
|
||||||
|
if targetDate.After(now.Add(ReminderMaxDuration)) {
|
||||||
|
return now, fmt.Errorf("Non credo riuscirei a ricordarmi qualcosa per così tanto")
|
||||||
|
}
|
||||||
|
return targetDate, nil
|
||||||
|
}
|
Reference in a new issue