You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

319 lines
8.2 KiB
Go

// test account (avicious.406+test@gmail.com) API key
// eZbV6TDcl2qUmtEAMLllN8qOHeb1hQiS8sVEoG2OmfqLym4UqihiFL83xgM2SLGPtz8HS2DeX45sk89B
// test offer id: https://hhtestnet.com/offers/F8W2srPJK2JKwYdh
// TODO: unmarshal json (encoding/json)
package main
import (
"fmt"
"log"
"os"
"flag"
"net/http"
"io/ioutil"
"encoding/json"
"errors"
"gosrc.io/xmpp"
"gosrc.io/xmpp/stanza"
"github.com/spf13/pflag"
"github.com/spf13/viper"
"strings"
"strconv"
"path"
"encoding/xml"
"time"
)
const (
// APIEndpoint = "https://hodlhodl.com/api/v1"
//TestAPIEndpoint = "https://hhtestnet.com/api/v1"
//APIkey = "***REMOVED***"
JobSchedulerInterval = 60 * time.Second
// Config
infoFormat = "====== "
defaultConfigFilePath = "./"
configFileName = "config"
configType = "yaml"
logStanzasOn = "logger_on"
logFilePath = "logfile_path"
//Keys in config
serverAddressKey = "full_address"
clientJid = "jid"
clientPass = "pass"
configContactSep = ";"
APIEndPoint = "testapiendpoint"
APIKey = "apikey"
)
var (
textChan = make(chan string, 5)
rawTextChan = make(chan string, 5)
killChan = make(chan error, 1)
errChan = make(chan error)
rosterChan = make(chan struct{})
logger *log.Logger
disconnectErr = errors.New("disconnecting client")
)
// Notification export
type Notification struct {
Status string `json:"status"`
Notifications []struct {
ID string `json:"id"`
Title string `json:"title"`
Body string `json:"body"`
Link string `json:"link"`
} `json:"notifications"`
}
type config struct {
Server map[string]string `mapstructure:"server"`
Client map[string]string `mapstructure:"client"`
Contacts string `string:"contact"`
Hodlhodl map[string]string `mapstructure:"hodlhodl"`
LogStanzas map[string]string `mapstructure:"logstanzas"`
}
func main() {
//body:= strings.NewReader(' -X POST -H "Authorization: Bearer ***REMOVED***" -H "Content-Type: application/json"`)
// ============================================================
// Parse the flag with the config directory path as argument
flag.String("c", defaultConfigFilePath, "Provide a path to the directory that contains the configuration"+
" file you want to use. Config file should be named \"config\" and be in YAML format..")
pflag.CommandLine.AddGoFlagSet(flag.CommandLine)
pflag.Parse()
// ==========================
// Read configuration
c := readConfig()
// Setup logger
on, err := strconv.ParseBool(c.LogStanzas[logStanzasOn])
if err != nil {
log.Panicln(err)
}
if on {
f, err := os.OpenFile(path.Join(c.LogStanzas[logFilePath], "logs.txt"), os.O_RDWR|os.O_APPEND|os.O_CREATE, 0666)
if err != nil {
log.Panicln(err)
}
logger = log.New(f, "", log.Lshortfile|log.Ldate|log.Ltime)
logger.SetOutput(f)
defer f.Close()
}
startClient(c)
}
func startClient(config *config) {
// Client Setup
clientCfg := &xmpp.Config {
TransportConfiguration: xmpp.TransportConfiguration{
Address: config.Server[serverAddressKey],
},
Jid: config.Client[clientJid],
Credential: xmpp.Password(config.Client[clientPass]),
Insecure: true,
}
var err error
var client *xmpp.Client
router := xmpp.NewRouter()
errorHandler:= func(err error) {
fmt.Println(err.Error())
}
if client, err = xmpp.NewClient(clientCfg, router, errorHandler); err != nil {
log.Panicln(fmt.Sprintf("Could not create a new client ! %s", err))
}
// Client connection
if err = client.Connect(); err != nil {
fmt.Sprintf("%sXMPP connection failed: %s", infoFormat, err)
fmt.Println("Failed to connect to server. Exiting...")
servConnFail := errors.New("failed to connect to server. Check your configuration ? Exiting")
errChan <- servConnFail
return
} else {
fmt.Println("Client is running")
}
/*client, err := xmpp.NewClient(clientCfg, router, errorHandler)
if err != nil {
log.Panicln(fmt.Sprintf("Could not create a new client ! %s", err))
//log.Fatalf("%+v", err)
} else {
fmt.Println("Client running....")
}*/
//Connection manager, reconect automatically
/*cm := xmpp.NewStreamManager(client, nil)
log.Fatal(cm.Run())*/
// ====================
// Start working
// fmt.Println("CONFIG.HODLHDOL :", config.Hodlhodl[APIKey])
timer := time.NewTicker(5 * time.Second)
notifications := make(chan string, 100)
go startMessaging(client, config, notifications)
for {
select {
case <- timer.C:
fmt.Println("cheking notifs ...")
notifications <- gethdlNotif(config.Hodlhodl[APIKey], config.Hodlhodl[APIEndPoint])
}
}
}
func startMessaging(client xmpp.Sender, config *config, notifications chan string) {
fmt.Println("START MESSAGING")
currentContact := strings.Split(config.Contacts, configContactSep)[1]
fmt.Println(infoFormat+"Now sending messages to "+currentContact+" in a private conversation\n")
fmt.Println("currentContacts", currentContact)
for {
select {
case notif := <-notifications:
// Test if notif is nil or skip this loop
if notif == "" { break ;}
fmt.Println("sending notification through xmpp")
reply := stanza.Message{Attrs: stanza.Attrs{To: currentContact, Type: stanza.MessageTypeChat}, Body: notif}
if logger != nil {
raw, _ := xml.Marshal(reply)
logger.Println(string(raw))
}
err := client.Send(reply)
if err != nil {
fmt.Printf("There was a problem sending the message : %v", reply)
return
}
case <-rosterChan:
fmt.Println("rosterchan")
}
}
}
func gethdlNotif(APIKey string, APIEndPoint string ) string {
fmt.Println("get notif")
req, err := http.NewRequest("POST", APIEndPoint + "/notifications/read", nil)
if err != nil {
fmt.Println(err)
}
req.Header.Add("Authorization", "Bearer " + APIKey)
req.Header.Set("Content-Type", "application/json")
resp, err := http.DefaultClient.Do(req)
if err!= nil {
fmt.Println(err)
}
//fmt.Println(resp.Status)
body, err := ioutil.ReadAll(resp.Body)
if err != nil {
fmt.Println(err)
} else {
res:= Notification{}
json.Unmarshal([]byte(body), &res)
//fmt.Println("RESULT title", res.Notifications[0].Title)
//fmt.Println("RESULT body", res.Notifications[0].Body)
//fmt.Println("res: ", res)
//fmt.Println("res.Notifications: ", res.Notifications)
if (len(res.Notifications) > 0) {
//fmt.Println("type of notif = ", reflect.TypeOf(res.Notifications[0]))
fmt.Println("Join: ", strings.Join([]string{res.Notifications[0].Title, res.Notifications[0].Body}, " "))
//fmt.Println("RESULT stirng(body)", string(body))
//fmt.Println("RESULTAT", string(body))
notif := strings.Join([]string{res.Notifications[0].Title, res.Notifications[0].Body}, " ")
return notif
}
}
defer resp.Body.Close()
fmt.Println("no notif empty string")
return ""
}
func readConfig() *config {
viper.SetConfigName(configFileName) // name of config file (without extension)
viper.BindPFlags(pflag.CommandLine)
viper.AddConfigPath(viper.GetString("c")) // path to look for the config file in
err := viper.ReadInConfig() // Find and read the config file
if err := viper.ReadInConfig(); err != nil {
if _, ok := err.(viper.ConfigFileNotFoundError); ok {
log.Fatalf("%s %s", err, "Please make sure you give a path to the directory of the config and not to the config itself.")
} else {
log.Panicln(err)
}
}
viper.SetConfigType(configType)
var config config
err = viper.Unmarshal(&config)
if err != nil {
panic(fmt.Errorf("Unable to decode Config: %s \n", err))
}
// Check if we have contacts to message
if len(strings.TrimSpace(config.Contacts)) == 0 {
log.Panicln("You appear to have no contacts to message !")
}
// Check logging
config.LogStanzas[logFilePath] = path.Clean(config.LogStanzas[logFilePath])
on, err := strconv.ParseBool(config.LogStanzas[logStanzasOn])
if err != nil {
log.Panicln(err)
}
if d, e := isDirectory(config.LogStanzas[logFilePath]); (e != nil || !d) && on {
log.Panicln("The log file path could not be found or is not a directory.")
}
fmt.Println("config in ReadConfig :", &config)
return &config
}
// If an error occurs, this is used to kill the client
func errorHandler(err error) {
killChan <- err
}
func isDirectory(path string) (bool, error) {
fileInfo, err := os.Stat(path)
if err != nil {
return false, err
}
return fileInfo.IsDir(), err
}