2020-06-21 19:51:33 +02:00
package main
import (
2021-11-13 03:40:43 +01:00
"crypto/rand"
"encoding/hex"
2020-06-21 19:54:07 +02:00
"encoding/json"
2021-11-06 16:33:16 +01:00
"fmt"
2021-12-05 14:46:59 +01:00
"math"
2021-11-06 16:33:16 +01:00
"regexp"
2021-12-05 15:39:14 +01:00
"sort"
2021-11-06 16:33:16 +01:00
"strconv"
"time"
2020-06-21 19:54:07 +02:00
2021-12-05 11:23:08 +01:00
"gonum.org/v1/plot"
"gonum.org/v1/plot/plotter"
"gonum.org/v1/plot/plotutil"
"gonum.org/v1/plot/vg"
2020-06-21 19:51:33 +02:00
tb "gopkg.in/tucnak/telebot.v2"
)
2021-11-06 16:33:16 +01:00
type Bot struct {
bot * tb . Bot
Config * TelegramConfig
}
2021-12-04 05:49:20 +01:00
type BotActionEntry struct {
Action string
2021-11-13 03:40:43 +01:00
CompanyID uint8
UserID int
Time time . Time
}
2021-12-04 05:49:20 +01:00
var botActionMap map [ string ] * BotActionEntry
2021-11-13 03:40:43 +01:00
2021-11-06 16:33:16 +01:00
func ( b * Bot ) Start ( ) {
var err error
b . bot , err = tb . NewBot ( tb . Settings {
Token : b . Config . Token ,
URL : b . Config . URL ,
Poller : & tb . LongPoller { Timeout : 10 * time . Second } ,
} )
failError ( err , "Bot.Start() : registering bot" )
2021-12-04 05:49:20 +01:00
botActionMap = make ( map [ string ] * BotActionEntry )
2021-11-13 03:40:43 +01:00
2021-11-06 16:33:16 +01:00
b . BotHandlers ( )
}
func ( b * Bot ) SendUser ( id int64 , msg string ) {
u := tb . User {
ID : int ( id ) ,
}
_ , err := b . bot . Send ( & u , msg )
logErrorDebug ( err , "Bot.SendUser()" )
}
func ( b * Bot ) SendChat ( chatID int64 , text string ) {
opt := tb . SendOptions {
ParseMode : tb . ModeDefault ,
}
ch := tb . Chat {
ID : chatID ,
}
_ , err := b . bot . Send ( & ch , text , & opt )
logErrorDebug ( err , "Bot.SendChat()" )
}
2020-06-21 19:51:33 +02:00
2021-12-05 11:23:08 +01:00
func ( b * Bot ) SendChatImage ( chatID int64 , image string ) {
opt := tb . SendOptions {
ParseMode : tb . ModeDefault ,
}
ch := tb . Chat {
ID : chatID ,
}
photo := & tb . Photo { File : tb . FromDisk ( image ) }
_ , err := b . bot . Send ( & ch , photo , & opt )
logErrorDebug ( err , "Bot.SendChatImage()" )
}
2021-11-06 16:33:16 +01:00
func ( b * Bot ) BotHandlers ( ) {
2020-06-22 11:02:04 +02:00
2021-11-06 16:33:16 +01:00
b . bot . Handle ( "/pause" , botPause )
b . bot . Handle ( "/unpause" , botUnpause )
b . bot . Handle ( "/register" , botRegister )
2021-11-09 06:24:42 +01:00
b . bot . Handle ( "/deregister" , botDeregister )
2021-11-06 16:33:16 +01:00
b . bot . Handle ( "/delete" , botDelete )
2021-12-08 12:50:55 +01:00
b . bot . Handle ( "/offline" , botOffline )
2021-11-06 16:33:16 +01:00
b . bot . Handle ( "/companies" , botCompanies )
b . bot . Handle ( "/clients" , botClients )
2021-12-04 05:49:20 +01:00
2021-11-10 05:56:53 +01:00
b . bot . Handle ( "/passwd" , botPasswd )
2021-11-13 06:44:57 +01:00
b . bot . Handle ( "/say" , botSay )
2021-11-28 11:31:49 +01:00
b . bot . Handle ( "/help" , botHelp )
2021-12-05 08:41:47 +01:00
2021-11-28 14:41:00 +01:00
b . bot . Handle ( "/version" , botVersion )
2021-12-05 08:41:47 +01:00
b . bot . Handle ( "/save" , botSave )
2020-06-21 19:51:33 +02:00
2021-12-04 05:49:20 +01:00
b . bot . Handle ( "/reset" , botReset )
b . bot . Handle ( "/ready" , botReady )
b . bot . Handle ( "/start" , botStart )
b . bot . Handle ( "/players" , botPlayers )
b . bot . Handle ( "/give" , botGive )
b . bot . Handle ( "/take" , botTake )
b . bot . Handle ( "/transfer" , botTransfer )
2021-12-05 11:23:08 +01:00
b . bot . Handle ( "/value" , botGraphValue )
2021-12-06 14:55:59 +01:00
b . bot . Handle ( "/value_delta" , botGraphValueDelta )
b . bot . Handle ( "/planes" , botGraphPlanes )
2021-12-06 15:36:27 +01:00
b . bot . Handle ( "/busses" , botGraphBusses )
b . bot . Handle ( "/trains" , botGraphTrains )
2021-12-05 11:23:08 +01:00
2021-11-06 16:33:16 +01:00
b . bot . Handle ( tb . OnPhoto , botPhoto )
b . bot . Handle ( tb . OnChannelPost , botChannelPost )
b . bot . Handle ( tb . OnQuery , botQuery )
b . bot . Handle ( tb . OnText , botText )
b . bot . Handle ( tb . OnDocument , botDocument )
go func ( ) {
time . Sleep ( time . Second )
b . SendUser ( b . Config . AdminID , fmt . Sprintf ( "Started (%s)" , version ) )
} ( )
b . bot . Start ( )
2020-06-21 19:51:33 +02:00
}
2021-12-08 13:15:14 +01:00
func botHelp ( m * tb . Message ) {
msg := ""
msg = fmt . Sprintf ( "%s/pause - pause the game\r\n" , msg )
msg = fmt . Sprintf ( "%s/unpause - unpause the game\r\n" , msg )
msg = fmt . Sprintf ( "%s/register - register company\r\n" , msg )
msg = fmt . Sprintf ( "%s/deregister - deregister company\r\n" , msg )
msg = fmt . Sprintf ( "%s/delete - delete company\r\n" , msg )
msg = fmt . Sprintf ( "%s/companies - list companies\r\n" , msg )
msg = fmt . Sprintf ( "%s/clients - list clients\r\n" , msg )
msg = fmt . Sprintf ( "%s/give - give time to player\r\n" , msg )
msg = fmt . Sprintf ( "%s/take - take time from player\r\n" , msg )
msg = fmt . Sprintf ( "%s/transfer - transfer time between players\r\n" , msg )
msg = fmt . Sprintf ( "%s/passwd - change passwd\r\n" , msg )
msg = fmt . Sprintf ( "%s/say - send msg to the game\r\n" , msg )
msg = fmt . Sprintf ( "%s/reset - reset the game\r\n" , msg )
msg = fmt . Sprintf ( "%s/start - start the game\r\n" , msg )
msg = fmt . Sprintf ( "%s/ready - set player as ready\r\n" , msg )
msg = fmt . Sprintf ( "%s/players - list players\r\n" , msg )
msg = fmt . Sprintf ( "%s/offline - set player offline\r\n" , msg )
msg = fmt . Sprintf ( "%s/value - value graph\r\n" , msg )
msg = fmt . Sprintf ( "%s/value_delta - delta value graph\r\n" , msg )
msg = fmt . Sprintf ( "%s/busses - busses graph\r\n" , msg )
msg = fmt . Sprintf ( "%s/trains - trains graph\r\n" , msg )
msg = fmt . Sprintf ( "%s/planes - planes graph\r\n" , msg )
msg = fmt . Sprintf ( "%s/version - version\r\n" , msg )
msg = fmt . Sprintf ( "%s/help - this\r\n" , msg )
bot . SendChat ( m . Chat . ID , msg )
return
}
2020-06-22 11:02:04 +02:00
func botPause ( m * tb . Message ) {
2021-11-06 16:33:16 +01:00
for userID , cc := range cfg . Clients {
if userID == m . Sender . ID {
if co , ok := srv . Status . Companies [ cc . CompanyID ] ; ok {
if clt , ok2 := srv . Status . Clients [ co . ClientID ] ; ok2 {
clt . Paused = true
2021-11-08 07:27:49 +01:00
if ! srv . Status . Paused {
srv . Pause ( )
} else {
bot . SendChat ( bot . Config . ChatID , "Game already paused." )
}
return
2021-11-06 16:33:16 +01:00
}
}
2020-06-22 11:13:07 +02:00
}
2021-11-06 16:33:16 +01:00
}
2021-11-08 07:27:49 +01:00
bot . SendChat ( bot . Config . ChatID , "You are not playing and cannot pause the game." )
2020-06-22 11:02:04 +02:00
return
}
func botUnpause ( m * tb . Message ) {
2021-11-06 16:33:16 +01:00
PrintText ( m )
for userID , cc := range cfg . Clients {
if userID == m . Sender . ID {
if co , ok := srv . Status . Companies [ cc . CompanyID ] ; ok {
if clt , ok2 := srv . Status . Clients [ co . ClientID ] ; ok2 {
clt . Paused = false
2021-11-08 07:27:49 +01:00
if ! srv . NeedPause ( ) {
srv . Unpause ( )
} else {
bot . SendChat ( bot . Config . ChatID , fmt . Sprintf ( "Cannot unpause : %s" , srv . NeedPauseReason ( ) ) )
}
return
2021-11-06 16:33:16 +01:00
}
}
2020-06-22 11:09:11 +02:00
}
2021-11-06 16:33:16 +01:00
}
2021-11-08 07:27:49 +01:00
bot . SendChat ( bot . Config . ChatID , "You are not playing and cannot unpause the game." )
2021-11-06 16:33:16 +01:00
return
}
2021-12-08 12:50:55 +01:00
func botOffline ( m * tb . Message ) {
if m . Sender . ID != int ( cfg . Telegram . AdminID ) {
bot . SendChat ( m . Chat . ID , "Only the admin can use this command." )
return
}
2021-12-08 12:54:01 +01:00
r := regexp . MustCompile ( "^\\/offline @(?P<Username>[a-zA-Z0-9]+)" )
2021-12-08 12:50:55 +01:00
if ! r . MatchString ( m . Text ) {
bot . SendChat ( m . Chat . ID , "Wrong format." )
return
}
uStr := r . ReplaceAllString ( m . Text , "${Username}" )
var u int
for ccID , cc := range cfg . Clients {
if cc . Username == uStr {
u = ccID
}
}
if u == 0 {
bot . SendChat ( m . Chat . ID , "No such user found." )
return
}
cc := cfg . Clients [ u ]
cc . Online = false
bot . SendChat ( m . Chat . ID , fmt . Sprintf ( "@%s is now offline." , uStr ) )
}
2021-11-06 16:33:16 +01:00
func botDelete ( m * tb . Message ) {
2021-11-28 14:41:00 +01:00
r := regexp . MustCompile ( "\\/delete (?P<CompanyID>[0-9]+)" )
2021-11-13 03:40:43 +01:00
id := uint8 ( 255 )
if r . MatchString ( m . Text ) {
2021-11-06 16:33:16 +01:00
ID64 , _ := strconv . ParseInt ( r . ReplaceAllString ( m . Text , "${CompanyID}" ) , 10 , 64 )
2021-11-13 03:40:43 +01:00
if m . Sender . ID == int ( bot . Config . AdminID ) {
id = uint8 ( ID64 )
} else if cc , ok := cfg . Clients [ m . Sender . ID ] ; ok && cc . CompanyID == uint8 ( ID64 ) {
id = cc . CompanyID
2021-11-12 02:17:25 +01:00
} else {
2021-11-13 03:40:43 +01:00
bot . SendChat ( m . Chat . ID , "Not authorized to delete" )
return
2021-11-12 02:17:25 +01:00
}
2021-11-13 03:40:43 +01:00
} else if cc , ok := cfg . Clients [ m . Sender . ID ] ; ok {
id = cc . CompanyID
2020-06-22 11:13:07 +02:00
} else {
2021-11-13 03:40:43 +01:00
bot . SendChat ( m . Chat . ID , "User not registered" )
return
}
if id == 255 {
bot . SendChat ( m . Chat . ID , "No company registered" )
return
}
if co , ok := srv . Status . Companies [ id ] ; ok {
b := make ( [ ] byte , 8 )
_ , err := rand . Read ( b )
logErrorDebug ( err , "botDelete : rand.Read" )
if err != nil {
bot . SendChat ( m . Chat . ID , "internal error" )
return
}
c := hex . EncodeToString ( b )
2021-12-04 05:49:20 +01:00
d := & BotActionEntry {
Action : "DeleteCompany" ,
2021-11-13 03:40:43 +01:00
CompanyID : id ,
UserID : m . Sender . ID ,
Time : time . Now ( ) ,
}
2021-12-04 05:49:20 +01:00
botActionMap [ c ] = d
2021-11-13 03:40:43 +01:00
bot . SendChat ( m . Chat . ID , fmt . Sprintf ( "Press /delete_%s to delete '%s'" , c , co . Name ) )
} else {
bot . SendChat ( m . Chat . ID , "Company doesn't exist" )
2021-11-06 16:33:16 +01:00
}
return
}
2021-12-04 06:24:45 +01:00
func botActuallyDelete ( m * tb . Message ) {
r := regexp . MustCompile ( "^\\/delete_(?P<Ref>[a-f0-9]{16})$" )
ref := r . ReplaceAllString ( m . Text , "${Ref}" )
a , ok := botActionMap [ ref ]
if ! ok {
bot . SendChat ( m . Chat . ID , "No corresponding request." )
return
}
if a . Action != "DeleteCompany" {
bot . SendChat ( m . Chat . ID , "Not a delete request." )
return
}
if a . UserID != m . Sender . ID {
bot . SendChat ( m . Chat . ID , "Requesting user has to confirm himself." )
return
}
if time . Now ( ) . Sub ( a . Time ) > time . Minute {
bot . SendChat ( m . Chat . ID , "Request expired." )
} else {
srv . DeleteCompany ( a . CompanyID )
bot . SendChat ( m . Chat . ID , "Company deleted." )
}
delete ( botActionMap , ref )
return
}
2021-11-06 16:33:16 +01:00
func botCompanies ( m * tb . Message ) {
str := "Companies :"
for k , v := range srv . Status . Companies {
2021-11-10 07:55:31 +01:00
str = str + "\r\n" + fmt . Sprintf ( " - %s (%d - %t)" , v . Name , k , v . Protected )
2021-11-06 16:33:16 +01:00
}
bot . SendChat ( m . Chat . ID , str )
}
func botClients ( m * tb . Message ) {
str := "Clients :"
for k , v := range srv . Status . Clients {
str = str + "\r\n" + fmt . Sprintf ( " - %s (%d) : company #%d" , v . Name , k , v . CompanyID )
}
bot . SendChat ( m . Chat . ID , str )
}
2021-12-04 05:49:20 +01:00
func botReset ( m * tb . Message ) {
if m . Sender . ID != int ( cfg . Telegram . AdminID ) {
bot . SendChat ( m . Chat . ID , "Only the admin can use this command." )
return
}
2021-12-04 06:24:45 +01:00
if ! cfg . Game . Started {
bot . SendChat ( m . Chat . ID , "Game is not started." )
return
}
2021-12-04 05:49:20 +01:00
b := make ( [ ] byte , 8 )
_ , err := rand . Read ( b )
logErrorDebug ( err , "botReset : rand.Read" )
if err != nil {
bot . SendChat ( m . Chat . ID , "internal error" )
return
}
c := hex . EncodeToString ( b )
d := & BotActionEntry {
Action : "ResetGame" ,
CompanyID : 0 ,
UserID : m . Sender . ID ,
Time : time . Now ( ) ,
}
botActionMap [ c ] = d
bot . SendChat ( m . Chat . ID , fmt . Sprintf ( "Press /reset_%s to reset the game" , c ) )
return
}
2021-12-04 06:24:45 +01:00
func botActuallyReset ( m * tb . Message ) {
r := regexp . MustCompile ( "^\\/reset_(?P<Ref>[a-f0-9]{16})$" )
ref := r . ReplaceAllString ( m . Text , "${Ref}" )
a , ok := botActionMap [ ref ]
if ! ok {
bot . SendChat ( m . Chat . ID , "No corresponding request." )
return
}
if a . Action != "ResetGame" {
bot . SendChat ( m . Chat . ID , "Not a reset request." )
return
}
if a . UserID != m . Sender . ID {
bot . SendChat ( m . Chat . ID , "Requesting user has to confirm himself." )
return
}
if time . Now ( ) . Sub ( a . Time ) > time . Minute {
bot . SendChat ( m . Chat . ID , "Request expired." )
} else {
2021-12-05 08:41:47 +01:00
cfg . Save ( "backup." + * configFlag )
2021-12-04 06:24:45 +01:00
cfg . Game . Started = false
2021-12-05 08:41:47 +01:00
cfg . Stats = make ( map [ uint8 ] map [ string ] * Stat )
2021-12-04 06:39:15 +01:00
for _ , cc := range cfg . Clients {
cc . Ready = false
cc . CompanyID = 255
cc . Online = false
cc . TimeLeft = 0
}
2021-12-04 06:24:45 +01:00
bot . SendChat ( m . Chat . ID , "Game resetted." )
}
delete ( botActionMap , ref )
return
}
2021-12-04 05:49:20 +01:00
func botStart ( m * tb . Message ) {
2021-12-04 06:24:45 +01:00
if cfg . Game . Started {
bot . SendChat ( m . Chat . ID , "Game already started." )
2021-12-04 05:49:20 +01:00
return
}
2021-12-04 06:24:45 +01:00
actuallyReady := true
for _ , cc := range cfg . Clients {
if ! cc . Ready {
actuallyReady = false
}
}
if m . Sender . ID != int ( cfg . Telegram . AdminID ) && ! actuallyReady {
bot . SendChat ( m . Chat . ID , "Not all players are ready. Only the admin can force the start." )
}
2021-12-04 05:49:20 +01:00
b := make ( [ ] byte , 8 )
_ , err := rand . Read ( b )
logErrorDebug ( err , "botStart : rand.Read" )
if err != nil {
bot . SendChat ( m . Chat . ID , "internal error" )
return
}
c := hex . EncodeToString ( b )
d := & BotActionEntry {
Action : "StartGame" ,
CompanyID : 0 ,
UserID : m . Sender . ID ,
Time : time . Now ( ) ,
}
botActionMap [ c ] = d
bot . SendChat ( m . Chat . ID , fmt . Sprintf ( "Press /start_%s to actually start game" , c ) )
return
}
2021-12-04 06:24:45 +01:00
func botActuallyStart ( m * tb . Message ) {
r := regexp . MustCompile ( "^\\/start_(?P<Ref>[a-f0-9]{16})$" )
ref := r . ReplaceAllString ( m . Text , "${Ref}" )
a , ok := botActionMap [ ref ]
if ! ok {
bot . SendChat ( m . Chat . ID , "No corresponding request." )
return
}
if a . Action != "StartGame" {
bot . SendChat ( m . Chat . ID , "Not a game start request." )
return
}
if a . UserID != m . Sender . ID {
bot . SendChat ( m . Chat . ID , "Requesting user has to confirm himself." )
return
}
if time . Now ( ) . Sub ( a . Time ) > time . Minute {
bot . SendChat ( m . Chat . ID , "Request expired." )
} else {
cfg . Game . Started = true
cfg . Game . StartDate = time . Now ( )
for _ , cc := range cfg . Clients {
cc . Ready = true
2021-12-04 06:39:15 +01:00
cc . TimeLeft = cfg . Game . StartingAllotment
2021-12-04 06:24:45 +01:00
}
bot . SendChat ( m . Chat . ID , "Game started !" )
}
delete ( botActionMap , ref )
return
}
2021-12-04 05:49:20 +01:00
func botReady ( m * tb . Message ) {
2021-12-04 06:24:45 +01:00
if cfg . Game . Started {
bot . SendChat ( m . Chat . ID , "Game is already started." )
return
}
2021-12-04 05:49:20 +01:00
cc , ok := cfg . Clients [ m . Sender . ID ]
if ! ok {
bot . SendChat ( m . Chat . ID , "Player not registered" )
return
}
ready := 0
waiting := 0
for _ , cc2 := range cfg . Clients {
if cc2 . Ready {
ready ++
} else {
waiting ++
}
}
if cc . Ready {
cc . Ready = false
2021-12-04 06:24:45 +01:00
ready --
waiting ++
2021-12-04 05:49:20 +01:00
bot . SendChat ( m . Chat . ID , fmt . Sprintf ( "Player not ready anymore. Only %d players ready now." , ready ) )
} else {
cc . Ready = true
2021-12-04 06:24:45 +01:00
ready ++
waiting --
2021-12-04 05:49:20 +01:00
bot . SendChat ( m . Chat . ID , fmt . Sprintf ( "Player is now ready. Still waiting for %d players." , waiting ) )
}
return
}
2021-11-06 16:33:16 +01:00
func botPlayers ( m * tb . Message ) {
2021-12-04 05:49:20 +01:00
if cfg . Game . Started {
botPlayersStarted ( m )
} else {
botPlayersWaiting ( m )
}
return
}
func botPlayersStarted ( m * tb . Message ) {
2021-11-08 15:24:34 +01:00
d1 := time . Now ( ) . Sub ( cfg . Game . StartDate )
days := int ( time . Duration ( d1 . Hours ( ) ) / 24 )
d2 := time . Duration ( days + 1 ) * ( time . Hour ) * 24 - d1
2021-11-28 14:25:35 +01:00
str := fmt . Sprintf ( "Update in %s\r\n" , d2 . Round ( time . Second ) )
2021-11-08 14:51:21 +01:00
2021-11-06 16:33:16 +01:00
online := ""
for _ , cc := range cfg . Clients {
if cc . Online {
2021-11-26 01:29:09 +01:00
if co , ok := srv . Status . Companies [ cc . CompanyID ] ; ok {
2021-11-28 14:25:35 +01:00
online = online + fmt . Sprintf ( " - %s (%s) : %s" , cc . Username , cc . TimeLeft . Round ( time . Second ) , co . Name ) + "\r\n"
2021-11-26 01:29:09 +01:00
} else {
2021-11-28 14:25:35 +01:00
online = online + fmt . Sprintf ( " - %s (%s) : none" , cc . Username , cc . TimeLeft . Round ( time . Second ) ) + "\r\n"
2021-11-26 01:29:09 +01:00
}
2021-11-06 16:33:16 +01:00
}
}
offline := ""
for _ , cc := range cfg . Clients {
2021-11-26 01:29:09 +01:00
if co , ok := srv . Status . Companies [ cc . CompanyID ] ; ok && ! cc . Online {
2021-11-28 14:25:35 +01:00
offline = offline + fmt . Sprintf ( " - %s (%s) : %s" , cc . Username , cc . TimeLeft . Round ( time . Second ) , co . Name ) + "\r\n"
2021-11-26 01:29:09 +01:00
} else {
2021-11-28 14:25:35 +01:00
offline = offline + fmt . Sprintf ( " - %s (%s) : none" , cc . Username , cc . TimeLeft . Round ( time . Second ) ) + "\r\n"
2021-11-06 16:33:16 +01:00
}
}
2021-11-08 14:51:21 +01:00
2021-11-06 16:33:16 +01:00
if len ( online ) > 0 {
str = str + "Players online :\r\n" + online
}
if len ( offline ) > 0 {
str = str + "Players offline :\r\n" + offline
}
2021-11-08 14:51:21 +01:00
2021-11-06 16:33:16 +01:00
bot . SendChat ( m . Chat . ID , str )
}
2021-12-04 05:49:20 +01:00
func botPlayersWaiting ( m * tb . Message ) {
msg := "Player status :\r\n"
ready := ""
waiting := ""
for _ , cc := range cfg . Clients {
if cc . Ready {
ready = ready + fmt . Sprintf ( " - %s" , cc . Username ) + "\r\n"
} else {
waiting = waiting + fmt . Sprintf ( " - %s" , cc . Username ) + "\r\n"
}
}
if len ( ready ) > 0 {
msg = msg + "Players ready :\r\n" + ready
}
if len ( waiting ) > 0 {
msg = msg + "Waiting for :\r\n" + waiting
}
bot . SendChat ( m . Chat . ID , msg )
}
2021-11-09 10:45:01 +01:00
func botGive ( m * tb . Message ) {
2021-11-13 03:40:43 +01:00
if m . Sender . ID != int ( cfg . Telegram . AdminID ) {
bot . SendChat ( m . Chat . ID , "Only the admin can use this command." )
return
}
2021-11-28 14:41:00 +01:00
r := regexp . MustCompile ( "^\\/give @(?P<Username>[a-zA-Z0-9]+) (?P<Duration>[a-z0-9]+)" )
2021-11-13 03:40:43 +01:00
if ! r . MatchString ( m . Text ) {
bot . SendChat ( m . Chat . ID , "Wrong format." )
return
}
uStr := r . ReplaceAllString ( m . Text , "${Username}" )
var u int
for ccID , cc := range cfg . Clients {
if cc . Username == uStr {
u = ccID
}
}
if u == 0 {
bot . SendChat ( m . Chat . ID , "No such user found." )
return
}
dStr := r . ReplaceAllString ( m . Text , "${Duration}" )
d , err := time . ParseDuration ( dStr )
logErrorDebug ( err , "botGive : time.ParseDuration" )
if err != nil {
bot . SendChat ( m . Chat . ID , "Cannot parse duration." )
}
cc := cfg . Clients [ u ]
cc . TimeLeft += d
2021-11-28 14:25:35 +01:00
bot . SendChat ( m . Chat . ID , fmt . Sprintf ( "@%s now has %s left." , uStr , cc . TimeLeft . Round ( time . Second ) ) )
2021-11-09 10:45:01 +01:00
}
2021-11-28 14:41:00 +01:00
func botVersion ( m * tb . Message ) {
bot . SendChat ( m . Chat . ID , version )
return
}
2021-12-05 08:41:47 +01:00
func botSave ( m * tb . Message ) {
if m . Sender . ID != int ( cfg . Telegram . AdminID ) {
bot . SendChat ( m . Chat . ID , "Only the admin can use this command." )
return
}
2021-12-05 09:20:12 +01:00
r := regexp . MustCompile ( "^\\/save (?P<Filename>[a-zA-Z0-9._\\/]+)" )
2021-12-05 08:41:47 +01:00
if ! r . MatchString ( m . Text ) {
bot . SendChat ( m . Chat . ID , "Wrong usage." )
return
}
filename := r . ReplaceAllString ( m . Text , "${Filename}" )
err := cfg . Save ( filename + ".json" )
logErrorDebug ( err , "botSave : Config.Save(%s)" , filename + ".json" )
if err != nil {
bot . SendChat ( m . Chat . ID , fmt . Sprintf ( "Error : %s" , err ) )
} else {
bot . SendChat ( m . Chat . ID , "Saved." )
}
return
}
2021-11-28 11:31:49 +01:00
func botTransfer ( m * tb . Message ) {
2021-11-28 14:41:00 +01:00
r := regexp . MustCompile ( "^\\/transfer @(?P<Username>[a-zA-Z0-9]+) (?P<Duration>[a-z0-9]+)" )
if ! r . MatchString ( m . Text ) {
bot . SendChat ( m . Chat . ID , "Wrong usage." )
return
}
2021-11-28 11:31:49 +01:00
ccFrom , ok := cfg . Clients [ m . Sender . ID ]
if ! ok {
bot . SendChat ( m . Chat . ID , "Client not registered." )
return
}
dStr := r . ReplaceAllString ( m . Text , "${Duration}" )
d , err := time . ParseDuration ( dStr )
logErrorDebug ( err , "botTransfer : time.ParseDuration" )
if err != nil {
bot . SendChat ( m . Chat . ID , "Cannot parse duration." )
return
}
if ccFrom . TimeLeft < d {
bot . SendChat ( m . Chat . ID , "Not enough time left for user." )
return
}
uStr := r . ReplaceAllString ( m . Text , "${Username}" )
var toID int
for ccID , cc := range cfg . Clients {
if cc . Username == uStr {
toID = ccID
}
}
if toID == 0 {
bot . SendChat ( m . Chat . ID , "No such user found." )
return
}
ccTo := cfg . Clients [ toID ]
ccTo . TimeLeft += d
ccFrom . TimeLeft -= d
2021-11-28 14:25:35 +01:00
bot . SendChat ( m . Chat . ID , fmt . Sprintf ( "@%s now has %s left.\r\n@%s has %s left." , uStr , ccTo . TimeLeft . Round ( time . Second ) , ccFrom . Username , ccFrom . TimeLeft . Round ( time . Second ) ) )
2021-11-28 11:31:49 +01:00
}
2021-11-09 10:45:01 +01:00
func botTake ( m * tb . Message ) {
2021-11-13 03:40:43 +01:00
if m . Sender . ID != int ( cfg . Telegram . AdminID ) {
bot . SendChat ( m . Chat . ID , "Only the admin can use this command." )
return
}
2021-11-28 14:41:00 +01:00
r := regexp . MustCompile ( "^\\/take @(?P<Username>[a-zA-Z0-9]+) (?P<Duration>[a-z0-9]+)" )
2021-11-13 03:40:43 +01:00
if ! r . MatchString ( m . Text ) {
bot . SendChat ( m . Chat . ID , "Wrong format." )
return
}
uStr := r . ReplaceAllString ( m . Text , "${Username}" )
var u int
for ccID , cc := range cfg . Clients {
if cc . Username == uStr {
u = ccID
}
}
if u == 0 {
bot . SendChat ( m . Chat . ID , "No such user found." )
return
}
dStr := r . ReplaceAllString ( m . Text , "${Duration}" )
d , err := time . ParseDuration ( dStr )
logErrorDebug ( err , "botGive : time.ParseDuration" )
if err != nil {
bot . SendChat ( m . Chat . ID , "Cannot parse duration." )
2021-11-28 11:31:49 +01:00
return
2021-11-13 03:40:43 +01:00
}
cc := cfg . Clients [ u ]
cc . TimeLeft -= d
2021-11-28 14:25:35 +01:00
bot . SendChat ( m . Chat . ID , fmt . Sprintf ( "@%s now has %s left." , uStr , cc . TimeLeft . Round ( time . Second ) ) )
2021-11-09 10:45:01 +01:00
}
2021-11-13 06:44:57 +01:00
func botSay ( m * tb . Message ) {
r := regexp . MustCompile ( "^\\/say( )+(?P<Message>.+)$" )
if ! r . MatchString ( m . Text ) {
bot . SendChat ( m . Chat . ID , "No message provided" )
return
}
msg := r . ReplaceAllString ( m . Text , "${Message}" )
2021-11-13 07:23:40 +01:00
px := PacketAdminRCon {
Packet : Packet { PType : AdminPacketAdminRCon } ,
2021-11-13 07:38:39 +01:00
Command : fmt . Sprintf ( "say \"@%s says : %s\"" , m . Sender . Username , msg ) ,
2021-11-13 06:44:57 +01:00
}
srv . Send ( px . Bytes ( ) )
return
}
2021-11-10 05:56:53 +01:00
func botPasswd ( m * tb . Message ) {
cc , ok := cfg . Clients [ m . Sender . ID ]
if ! ok {
bot . SendChat ( m . Chat . ID , "User not registered." )
return
}
2021-11-10 06:41:37 +01:00
if cc . CompanyID == 255 {
bot . SendChat ( m . Chat . ID , "No company registered." )
return
}
co , ok := srv . Status . Companies [ cc . CompanyID ]
if ! ok {
bot . SendChat ( m . Chat . ID , "Registered company doesn't exist." )
cc . CompanyID = 255
return
}
2021-11-10 06:02:52 +01:00
r := regexp . MustCompile ( "^\\/passwd( )+(?P<Passwd>[^ ]+)$" )
2021-11-10 06:41:37 +01:00
if ! r . MatchString ( m . Text ) {
2021-11-10 05:56:53 +01:00
bot . SendChat ( m . Chat . ID , "No passwd provided" )
2021-11-10 06:41:37 +01:00
return
2021-11-10 05:56:53 +01:00
}
2021-11-10 06:41:37 +01:00
// we have a parameter
cc . Passwd = r . ReplaceAllString ( m . Text , "${Passwd}" )
err := bot . bot . Delete ( m )
logErrorDebug ( err , "botPasswd : Delete" )
2021-11-10 07:43:55 +01:00
srv . SetPasswd ( co . CompanyExtlID , cc . Passwd )
2021-11-10 06:41:37 +01:00
bot . SendUser ( int64 ( m . Sender . ID ) , fmt . Sprintf ( "Passwd set to \"%s\"" , cc . Passwd ) )
2021-11-10 05:56:53 +01:00
return
}
2021-11-09 06:24:42 +01:00
func botDeregister ( m * tb . Message ) {
2021-11-28 14:41:00 +01:00
r := regexp . MustCompile ( "^\\/deregister @(?P<Username>[a-zA-Z0-9]+)$" )
if r . MatchString ( m . Text ) {
if m . Sender . ID != int ( cfg . Telegram . AdminID ) {
bot . SendChat ( m . Chat . ID , "Not admin." )
return
}
uStr := r . ReplaceAllString ( m . Text , "${Username}" )
var uID int
for ccID , cc := range cfg . Clients {
if cc . Username == uStr {
uID = ccID
}
}
if uID == 0 {
bot . SendChat ( m . Chat . ID , "No such user found." )
return
}
cc := cfg . Clients [ uID ]
if cc . CompanyID != 255 {
for coID , co := range srv . Status . Companies {
if coID == cc . CompanyID {
cc . CompanyID = 255
bot . SendChat ( m . Chat . ID , fmt . Sprintf ( "Deregistered from %s. %s playable left." , co . Name , cc . TimeLeft . Round ( time . Second ) ) )
return
}
}
logInfoAlert ( "botRegister : %s : no such CompanyID : %d" , cc . Username , cc . CompanyID )
cc . CompanyID = 255
bot . SendChat ( m . Chat . ID , fmt . Sprintf ( "Registered company didn't exist anymore. %s playable left." , cc . TimeLeft . Round ( time . Second ) ) )
return
}
return
}
2021-11-09 06:24:42 +01:00
cc , ok := cfg . Clients [ m . Sender . ID ]
if ! ok {
cc = & ClientConfig {
UserID : m . Sender . ID ,
Username : m . Sender . Username ,
CompanyID : 255 ,
TimeLeft : 0 ,
}
cfg . Clients [ m . Sender . ID ] = cc
bot . SendChat ( m . Chat . ID , "User isn't registered." )
return
}
if cc . CompanyID != 255 {
for coID , co := range srv . Status . Companies {
if coID == cc . CompanyID {
cc . CompanyID = 255
2021-11-28 14:25:35 +01:00
bot . SendChat ( m . Chat . ID , fmt . Sprintf ( "Deregistered from %s. %s playable left." , co . Name , cc . TimeLeft . Round ( time . Second ) ) )
2021-11-09 06:24:42 +01:00
return
}
}
logInfoAlert ( "botRegister : %s : no such CompanyID : %d" , cc . Username , cc . CompanyID )
cc . CompanyID = 255
2021-11-28 14:25:35 +01:00
bot . SendChat ( m . Chat . ID , fmt . Sprintf ( "Registered company didn't exist anymore. %s playable left." , cc . TimeLeft . Round ( time . Second ) ) )
2021-11-09 06:24:42 +01:00
return
}
return
}
2021-11-06 16:33:16 +01:00
func botRegister ( m * tb . Message ) {
cc , ok := cfg . Clients [ m . Sender . ID ]
if ! ok {
cc = & ClientConfig {
UserID : m . Sender . ID ,
Username : m . Sender . Username ,
CompanyID : 255 ,
2021-11-09 06:24:42 +01:00
TimeLeft : 0 ,
2021-12-04 06:39:15 +01:00
Ready : cfg . Game . Started ,
2021-11-06 16:33:16 +01:00
}
cfg . Clients [ m . Sender . ID ] = cc
2021-11-09 06:24:42 +01:00
} else {
if cc . CompanyID != 255 {
for coID , co := range srv . Status . Companies {
if coID == cc . CompanyID {
bot . SendChat ( m . Chat . ID , fmt . Sprintf ( "Already registered %s. Please /deregister first." , co . Name ) )
return
}
}
logInfoAlert ( "botRegister : %s : no such CompanyID : %d" , cc . Username , cc . CompanyID )
cc . CompanyID = 255
}
2021-11-06 16:33:16 +01:00
}
2021-11-09 06:24:42 +01:00
2021-11-06 16:33:16 +01:00
coList := make ( map [ uint8 ] struct { } )
for coID , _ := range srv . Status . Companies {
coList [ coID ] = struct { } { }
2020-06-22 11:09:11 +02:00
}
2021-11-06 16:33:16 +01:00
for _ , c := range cfg . Clients {
if c . CompanyID != 255 {
if _ , ok := coList [ c . CompanyID ] ; ! ok {
logInfoAlert ( "botRegister : %s : no such CompanyID : %d" , c . Username , c . CompanyID )
c . CompanyID = 255
} else {
delete ( coList , c . CompanyID )
}
}
}
2021-11-09 06:24:42 +01:00
2021-11-06 16:33:16 +01:00
if len ( coList ) == 0 {
bot . SendChat ( m . Chat . ID , "No company to register" )
return
}
2021-11-09 06:24:42 +01:00
r := regexp . MustCompile ( "^\\/register( )+(?P<Company>[a-zA-Z\\.\\-0-9 ]+)$" )
if r . MatchString ( m . Text ) {
// we have a parameter
coName := r . ReplaceAllString ( m . Text , "${Company}" )
for coID , co := range srv . Status . Companies {
if co . Name == coName {
for _ , c := range cfg . Clients {
if c . CompanyID == coID {
bot . SendChat ( m . Chat . ID , fmt . Sprintf ( "Company %s is already registered to @%s" , coName , c . Username ) )
return
}
}
cc . CompanyID = coID
if cc . TimeLeft == 0 {
days := int ( time . Now ( ) . Sub ( cfg . Game . StartDate ) . Hours ( ) / 24 )
cc . TimeLeft = cfg . Game . StartingAllotment + cfg . Game . DailyAllotment * time . Duration ( days )
}
bot . SendChat ( m . Chat . ID , fmt . Sprintf ( "@%s registered %s (with %s playable)" , cc . Username , srv . Status . Companies [ cc . CompanyID ] . Name , cc . TimeLeft ) )
return
}
}
bot . SendChat ( m . Chat . ID , fmt . Sprintf ( "Can't find company %s" , coName ) )
return
}
2021-11-06 16:33:16 +01:00
if len ( coList ) == 1 {
for id , _ := range coList {
cc . CompanyID = id
2021-12-04 06:39:15 +01:00
if cc . TimeLeft == 0 && cfg . Game . Started {
2021-11-09 06:24:42 +01:00
days := int ( time . Now ( ) . Sub ( cfg . Game . StartDate ) . Hours ( ) / 24 )
cc . TimeLeft = cfg . Game . StartingAllotment + cfg . Game . DailyAllotment * time . Duration ( days )
2021-12-04 06:39:15 +01:00
bot . SendChat ( m . Chat . ID , fmt . Sprintf ( "@%s registered %s (with %s playable)" , cc . Username , srv . Status . Companies [ cc . CompanyID ] . Name , cc . TimeLeft . Round ( time . Second ) ) )
} else {
bot . SendChat ( m . Chat . ID , fmt . Sprintf ( "@%s registered %s" , cc . Username , srv . Status . Companies [ cc . CompanyID ] . Name ) )
2021-11-09 06:24:42 +01:00
}
2021-11-06 16:33:16 +01:00
return
}
}
bot . SendChat ( m . Chat . ID , "More than one company unregistered. Wait for bot update (poke @tiennou)" )
2020-06-22 11:02:04 +02:00
return
}
2021-12-05 11:23:08 +01:00
func botGraphValue ( m * tb . Message ) {
2021-12-05 14:46:59 +01:00
var (
maxVal float64
unitFactor float64
unitName string
)
for coID , dStats := range cfg . Stats {
if cfg . CompanyIsRegistered ( coID ) {
for _ , stat := range dStats {
valueFloat := float64 ( stat . CompanyValueLastQuarter )
if math . Abs ( valueFloat ) > maxVal {
maxVal = math . Abs ( valueFloat )
}
}
}
}
if maxVal > 1000000000 {
unitFactor = 1000000000
unitName = "billion"
} else if maxVal > 1000000 {
unitFactor = 1000000
unitName = "million"
} else {
unitFactor = 1
unitName = ""
}
2021-12-05 11:23:08 +01:00
var vals map [ uint8 ] plotter . XYs
vals = make ( map [ uint8 ] plotter . XYs )
for coID , dStats := range cfg . Stats {
if cfg . CompanyIsRegistered ( coID ) {
vals [ coID ] = make ( plotter . XYs , 0 )
for dStr , stat := range dStats {
d , err := time . Parse ( "20060102" , dStr )
logErrorDebug ( err , "botGraphValue : time.Parse" )
if err != nil {
bot . SendChat ( m . Chat . ID , fmt . Sprintf ( "time.Parse : %s" , err ) )
return
}
dateFloat := float64 ( d . Year ( ) ) + float64 ( d . Month ( ) - 1 ) / 12
valueFloat := float64 ( stat . CompanyValueLastQuarter )
pt := plotter . XY {
X : dateFloat ,
2021-12-05 14:46:59 +01:00
Y : valueFloat / unitFactor ,
2021-12-05 11:23:08 +01:00
}
vals [ coID ] = append ( vals [ coID ] , pt )
}
2021-12-05 15:39:14 +01:00
sort . Slice ( vals [ coID ] , func ( i , j int ) bool { return vals [ coID ] [ i ] . X < vals [ coID ] [ j ] . X } )
2021-12-05 11:23:08 +01:00
}
}
p := plot . New ( )
p . Title . Text = "Company Values"
p . X . Label . Text = "Year"
2021-12-05 14:46:59 +01:00
if unitName != "" {
p . Y . Label . Text = fmt . Sprintf ( "Value (%s)" , unitName )
} else {
p . Y . Label . Text = "Value"
}
2021-12-05 11:23:08 +01:00
2021-12-05 14:46:59 +01:00
i := 0
2021-12-05 11:23:08 +01:00
for coID , xys := range vals {
cc := cfg . GetCompanyClient ( coID )
2021-12-05 14:46:59 +01:00
l , s , err := plotter . NewLinePoints ( xys )
2021-12-06 14:55:59 +01:00
logErrorDebug ( err , "botGraphValue : plotter.NewLinePoints" )
2021-12-05 11:23:08 +01:00
if err != nil {
2021-12-05 14:46:59 +01:00
bot . SendChat ( m . Chat . ID , fmt . Sprintf ( "plotter.NewLinePoints : %s" , err ) )
2021-12-05 11:23:08 +01:00
return
}
2021-12-05 14:46:59 +01:00
l . Color = plotutil . Color ( i )
l . Dashes = plotutil . Dashes ( 2 )
s . Color = plotutil . Color ( i )
s . Shape = plotutil . Shape ( 0 )
p . Add ( l )
p . Add ( s )
p . Legend . Add ( cc . Username , l , s )
i ++
2021-12-05 11:23:08 +01:00
}
2021-12-05 15:11:15 +01:00
err := p . Save ( 6 * vg . Inch , 4 * vg . Inch , "/app/data/points.png" )
2021-12-06 14:55:59 +01:00
logErrorDebug ( err , "botGraphValue : plot.Save" )
if err != nil {
bot . SendChat ( m . Chat . ID , fmt . Sprintf ( "plot.Save : %s" , err ) )
return
}
bot . SendChatImage ( m . Chat . ID , "/app/data/points.png" )
return
}
func botGraphValueDelta ( m * tb . Message ) {
var (
maxVal float64
unitFactor float64
unitName string
)
var vals map [ uint8 ] plotter . XYs
vals = make ( map [ uint8 ] plotter . XYs )
for coID , dStats := range cfg . Stats {
if cfg . CompanyIsRegistered ( coID ) {
vals [ coID ] = make ( plotter . XYs , 0 )
for dStr , stat := range dStats {
d , err := time . Parse ( "20060102" , dStr )
logErrorDebug ( err , "botGraphValueDelta : time.Parse" )
if err != nil {
bot . SendChat ( m . Chat . ID , fmt . Sprintf ( "time.Parse : %s" , err ) )
return
}
pt := plotter . XY {
2021-12-06 15:23:13 +01:00
X : float64 ( d . Year ( ) ) + float64 ( d . Month ( ) - 1 ) / 12 ,
Y : float64 ( stat . CompanyValueLastQuarter ) ,
2021-12-06 14:55:59 +01:00
}
vals [ coID ] = append ( vals [ coID ] , pt )
}
sort . Slice ( vals [ coID ] , func ( i , j int ) bool { return vals [ coID ] [ i ] . X < vals [ coID ] [ j ] . X } )
}
}
for coID , v := range vals {
2021-12-08 13:15:14 +01:00
if len ( v ) <= 3 {
delete ( vals , coID )
2021-12-06 15:36:27 +01:00
} else {
2021-12-08 13:15:14 +01:00
v0 := v [ 0 ] . Y
v1 := v [ 1 ] . Y
v2 := v [ 2 ] . Y
for i := 3 ; i < len ( v ) ; i ++ {
v0 = v1
v1 = v2
v2 = v [ i ] . Y
v [ i ] . Y = ( v0 + v1 + v2 ) / 3
}
vals [ coID ] = v [ 3 : ]
2021-12-06 15:36:27 +01:00
}
}
2021-12-06 14:55:59 +01:00
if maxVal > 1000000000 {
unitFactor = 1000000000
unitName = "billion"
} else if maxVal > 1000000 {
unitFactor = 1000000
unitName = "million"
} else {
unitFactor = 1
unitName = ""
}
2021-12-06 15:11:21 +01:00
logInfoDebug ( "botGraphValueDelta : unit set to %s (factor : %f)" , unitName , unitFactor )
2021-12-06 14:55:59 +01:00
for coID , v := range vals {
for i := 1 ; i < len ( vals ) - 1 ; i ++ {
v [ i ] . Y = v [ i ] . Y / unitFactor
2021-12-06 15:11:21 +01:00
if math . IsNaN ( v [ i ] . Y ) {
logInfoDebug ( "botGraphValueDelta : NaN : %d / %f" , coID , v [ i ] . X )
}
2021-12-06 14:55:59 +01:00
}
vals [ coID ] = v
}
p := plot . New ( )
p . Title . Text = "Company Values (delta)"
p . X . Label . Text = "Year"
if unitName != "" {
p . Y . Label . Text = fmt . Sprintf ( "Variation (%s)" , unitName )
} else {
p . Y . Label . Text = "Variation"
}
i := 0
for coID , xys := range vals {
cc := cfg . GetCompanyClient ( coID )
l , s , err := plotter . NewLinePoints ( xys )
logErrorDebug ( err , "botGraphValueDelta : plotter.NewLinePoints" )
if err != nil {
bot . SendChat ( m . Chat . ID , fmt . Sprintf ( "plotter.NewLinePoints : %s" , err ) )
return
}
l . Color = plotutil . Color ( i )
l . Dashes = plotutil . Dashes ( 2 )
s . Color = plotutil . Color ( i )
s . Shape = plotutil . Shape ( 0 )
p . Add ( l )
p . Add ( s )
p . Legend . Add ( cc . Username , l , s )
i ++
}
err := p . Save ( 6 * vg . Inch , 4 * vg . Inch , "/app/data/points.png" )
logErrorDebug ( err , "botGraphValueDelta : plot.Save" )
if err != nil {
bot . SendChat ( m . Chat . ID , fmt . Sprintf ( "plot.Save : %s" , err ) )
return
}
bot . SendChatImage ( m . Chat . ID , "/app/data/points.png" )
return
}
func botGraphPlanes ( m * tb . Message ) {
var planes , airports map [ uint8 ] plotter . XYs
planes = make ( map [ uint8 ] plotter . XYs )
airports = make ( map [ uint8 ] plotter . XYs )
for coID , dStats := range cfg . Stats {
if cfg . CompanyIsRegistered ( coID ) {
planes [ coID ] = make ( plotter . XYs , 0 )
for dStr , stat := range dStats {
d , err := time . Parse ( "20060102" , dStr )
logErrorDebug ( err , "botGraphPlanes : time.Parse" )
if err != nil {
bot . SendChat ( m . Chat . ID , fmt . Sprintf ( "time.Parse : %s" , err ) )
return
}
dateFloat := float64 ( d . Year ( ) ) + float64 ( d . Month ( ) - 1 ) / 12
pt := plotter . XY {
X : dateFloat ,
Y : float64 ( stat . Planes ) ,
}
planes [ coID ] = append ( planes [ coID ] , pt )
pt = plotter . XY {
X : dateFloat ,
Y : float64 ( stat . Airports ) ,
}
airports [ coID ] = append ( airports [ coID ] , pt )
}
sort . Slice ( planes [ coID ] , func ( i , j int ) bool { return planes [ coID ] [ i ] . X < planes [ coID ] [ j ] . X } )
sort . Slice ( airports [ coID ] , func ( i , j int ) bool { return airports [ coID ] [ i ] . X < airports [ coID ] [ j ] . X } )
}
}
p := plot . New ( )
p . Title . Text = "Planes summary"
p . X . Label . Text = "Year"
p . Y . Label . Text = "Planes"
i := 0
for coID , xys := range planes {
cc := cfg . GetCompanyClient ( coID )
l , s , err := plotter . NewLinePoints ( xys )
logErrorDebug ( err , "botGraphPlanes : plotter.NewLinePoints" )
if err != nil {
bot . SendChat ( m . Chat . ID , fmt . Sprintf ( "plotter.NewLinePoints : %s" , err ) )
return
}
l . Color = plotutil . Color ( i )
l . Dashes = plotutil . Dashes ( 2 )
s . Color = plotutil . Color ( i )
s . Shape = plotutil . Shape ( 0 )
p . Add ( l )
p . Add ( s )
p . Legend . Add ( cc . Username , l , s )
i ++
}
err := p . Save ( 6 * vg . Inch , 4 * vg . Inch , "/app/data/points.png" )
logErrorDebug ( err , "botGraphPlanes : plot.Save" )
2021-12-05 11:23:08 +01:00
if err != nil {
bot . SendChat ( m . Chat . ID , fmt . Sprintf ( "plot.Save : %s" , err ) )
return
}
bot . SendChatImage ( m . Chat . ID , "/app/data/points.png" )
return
}
2021-12-06 15:23:13 +01:00
func botGraphBusses ( m * tb . Message ) {
var busses , busStops map [ uint8 ] plotter . XYs
busses = make ( map [ uint8 ] plotter . XYs )
busStops = make ( map [ uint8 ] plotter . XYs )
for coID , dStats := range cfg . Stats {
if cfg . CompanyIsRegistered ( coID ) {
busses [ coID ] = make ( plotter . XYs , 0 )
for dStr , stat := range dStats {
d , err := time . Parse ( "20060102" , dStr )
logErrorDebug ( err , "botGraphBusses : time.Parse" )
if err != nil {
bot . SendChat ( m . Chat . ID , fmt . Sprintf ( "time.Parse : %s" , err ) )
return
}
dateFloat := float64 ( d . Year ( ) ) + float64 ( d . Month ( ) - 1 ) / 12
pt := plotter . XY {
X : dateFloat ,
Y : float64 ( stat . Busses ) ,
}
busses [ coID ] = append ( busses [ coID ] , pt )
pt = plotter . XY {
X : dateFloat ,
Y : float64 ( stat . BusStops ) ,
}
busStops [ coID ] = append ( busStops [ coID ] , pt )
}
sort . Slice ( busses [ coID ] , func ( i , j int ) bool { return busses [ coID ] [ i ] . X < busses [ coID ] [ j ] . X } )
sort . Slice ( busStops [ coID ] , func ( i , j int ) bool { return busStops [ coID ] [ i ] . X < busStops [ coID ] [ j ] . X } )
}
}
p := plot . New ( )
p . Title . Text = "Busses summary"
p . X . Label . Text = "Year"
p . Y . Label . Text = "Busses"
i := 0
for coID , xys := range busses {
cc := cfg . GetCompanyClient ( coID )
l , s , err := plotter . NewLinePoints ( xys )
logErrorDebug ( err , "botGraphBusses : plotter.NewLinePoints" )
if err != nil {
bot . SendChat ( m . Chat . ID , fmt . Sprintf ( "plotter.NewLinePoints : %s" , err ) )
return
}
l . Color = plotutil . Color ( i )
l . Dashes = plotutil . Dashes ( 2 )
s . Color = plotutil . Color ( i )
s . Shape = plotutil . Shape ( 0 )
p . Add ( l )
p . Add ( s )
p . Legend . Add ( cc . Username , l , s )
i ++
}
err := p . Save ( 6 * vg . Inch , 4 * vg . Inch , "/app/data/points.png" )
logErrorDebug ( err , "botGraphBusses : plot.Save" )
if err != nil {
bot . SendChat ( m . Chat . ID , fmt . Sprintf ( "plot.Save : %s" , err ) )
return
}
bot . SendChatImage ( m . Chat . ID , "/app/data/points.png" )
return
}
func botGraphTrains ( m * tb . Message ) {
var trains , trainStations map [ uint8 ] plotter . XYs
trains = make ( map [ uint8 ] plotter . XYs )
trainStations = make ( map [ uint8 ] plotter . XYs )
for coID , dStats := range cfg . Stats {
if cfg . CompanyIsRegistered ( coID ) {
trains [ coID ] = make ( plotter . XYs , 0 )
for dStr , stat := range dStats {
d , err := time . Parse ( "20060102" , dStr )
logErrorDebug ( err , "botGraphTrains : time.Parse" )
if err != nil {
bot . SendChat ( m . Chat . ID , fmt . Sprintf ( "time.Parse : %s" , err ) )
return
}
dateFloat := float64 ( d . Year ( ) ) + float64 ( d . Month ( ) - 1 ) / 12
pt := plotter . XY {
X : dateFloat ,
Y : float64 ( stat . Trains ) ,
}
trains [ coID ] = append ( trains [ coID ] , pt )
pt = plotter . XY {
X : dateFloat ,
Y : float64 ( stat . TrainStations ) ,
}
trainStations [ coID ] = append ( trainStations [ coID ] , pt )
}
sort . Slice ( trains [ coID ] , func ( i , j int ) bool { return trains [ coID ] [ i ] . X < trains [ coID ] [ j ] . X } )
sort . Slice ( trainStations [ coID ] , func ( i , j int ) bool { return trainStations [ coID ] [ i ] . X < trainStations [ coID ] [ j ] . X } )
}
}
p := plot . New ( )
p . Title . Text = "Trains summary"
p . X . Label . Text = "Year"
p . Y . Label . Text = "Trains"
i := 0
for coID , xys := range trains {
cc := cfg . GetCompanyClient ( coID )
l , s , err := plotter . NewLinePoints ( xys )
logErrorDebug ( err , "botGraphTrains : plotter.NewLinePoints" )
if err != nil {
bot . SendChat ( m . Chat . ID , fmt . Sprintf ( "plotter.NewLinePoints : %s" , err ) )
return
}
l . Color = plotutil . Color ( i )
l . Dashes = plotutil . Dashes ( 2 )
s . Color = plotutil . Color ( i )
s . Shape = plotutil . Shape ( 0 )
p . Add ( l )
p . Add ( s )
p . Legend . Add ( cc . Username , l , s )
i ++
}
err := p . Save ( 6 * vg . Inch , 4 * vg . Inch , "/app/data/points.png" )
logErrorDebug ( err , "botGraphTrains : plot.Save" )
if err != nil {
bot . SendChat ( m . Chat . ID , fmt . Sprintf ( "plot.Save : %s" , err ) )
return
}
bot . SendChatImage ( m . Chat . ID , "/app/data/points.png" )
return
}
2020-06-21 19:51:33 +02:00
func PrintText ( m * tb . Message ) {
logInfoDebug ( "[%d] %s(%d) | %s(%d) : %s\n" , m . ID , m . Chat . Title , m . Chat . ID , m . Sender . Username , m . Sender . ID , m . Text )
return
}
func botPhoto ( m * tb . Message ) {
logInfoDebug ( "botPhoto :" , m . Text )
// photos only
}
func botDocument ( m * tb . Message ) {
logInfoDebug ( "botDocument : %s (%d bytes)\n" , m . Document . FileName , m . Document . File . FileSize )
// documents only
}
func botChannelPost ( m * tb . Message ) {
PrintText ( m )
b , _ := json . Marshal ( m )
2020-06-21 19:54:07 +02:00
logInfoDebug ( "botChannelPost : %s\n" , string ( b ) )
2020-06-21 19:51:33 +02:00
// channel posts only
}
func botQuery ( q * tb . Query ) {
logInfoDebug ( "botQuery" )
// incoming inline queries
}
func botText ( m * tb . Message ) {
2021-12-04 05:49:20 +01:00
2021-11-28 14:41:00 +01:00
r := regexp . MustCompile ( "^\\/delete_(?P<Ref>[a-f0-9]{16})$" )
2021-11-13 03:40:43 +01:00
if r . MatchString ( m . Text ) {
2021-12-04 06:24:45 +01:00
botActuallyDelete ( m )
2021-12-04 05:49:20 +01:00
return
}
r = regexp . MustCompile ( "^\\/reset_(?P<Ref>[a-f0-9]{16})$" )
if r . MatchString ( m . Text ) {
2021-12-04 06:24:45 +01:00
botActuallyReset ( m )
2021-12-04 05:49:20 +01:00
return
}
r = regexp . MustCompile ( "^\\/start_(?P<Ref>[a-f0-9]{16})$" )
if r . MatchString ( m . Text ) {
2021-12-04 06:24:45 +01:00
botActuallyStart ( m )
2021-11-13 03:40:43 +01:00
return
}
2021-12-04 05:49:20 +01:00
2020-06-21 19:51:33 +02:00
PrintText ( m )
}