From 9df272c07cf418681e84dc53403bd2bad915dada Mon Sep 17 00:00:00 2001 From: ViViDboarder Date: Fri, 19 Sep 2014 18:32:10 -0700 Subject: [PATCH] Stuff --- gopush.go | 103 +++++++++++++++++++++ goson/goson.go | 136 +++++++++++++++++++++++++++ pushbullet/pushbullet.go | 194 +++++++++++++++++++++++++++++++++++++++ 3 files changed, 433 insertions(+) create mode 100644 gopush.go create mode 100644 goson/goson.go create mode 100644 pushbullet/pushbullet.go diff --git a/gopush.go b/gopush.go new file mode 100644 index 0000000..3bbe816 --- /dev/null +++ b/gopush.go @@ -0,0 +1,103 @@ +package main + +import ( + "flag" + "fmt" + "os" + + "./goson" + "./pushbullet" +) + +type Options struct { + Token string + Message string + Device string + Push bool + List bool + SetActive bool +} + +var options = Options{} + +func loadArgs() { + token := flag.String("token", "", "Your API Token") + activeDevice := flag.String("d", "", "Set default device") + + flag.Parse() + + options.Token = *token + options.Device = *activeDevice + + if options.Device != "" { + options.SetActive = true + } + + // Positional args + if len(flag.Args()) == 0 { + options.List = true + } else if len(flag.Args()) == 1 { + options.Message = flag.Args()[0] + options.Push = true + } else if len(flag.Args()) == 2 { + options.Device = flag.Args()[0] + options.Message = flag.Args()[1] + options.Push = true + } +} + +func main() { + loadArgs() + + config := goson.LoadConfig("gopush") + + var ok bool + if options.Token != "" { + config.Set("token", options.Token) + } else { + options.Token, ok = config.GetString("token") + + if !ok { + fmt.Println("No token found") + os.Exit(1) + } + } + + pb := pushbullet.New(options.Token) + + if options.Device == "" { + activeDeviceIden, ok := config.GetString("activeDeviceIden") + if ok { + options.Device = activeDeviceIden + } + } + + pb.SetActiveDevice(options.Device) + + if options.SetActive { + config.Set("activeDeviceIden", pb.ActiveDevice.Iden) + } + + config.Write() + + if options.Push { + pb.Push(options.Message) + } else if options.List { + devices := pb.GetDevices() + PrintDevices(devices, pb.ActiveDevice) + } +} + +func PrintDevices(devices []pushbullet.Device, activeDevice pushbullet.Device) { + fmt.Println("Devices:") + var prefix string + for _, device := range devices { + if device.Iden == activeDevice.Iden { + prefix = " *" + } else { + prefix = " " + } + + fmt.Println(prefix + device.Format()) + } +} diff --git a/goson/goson.go b/goson/goson.go new file mode 100644 index 0000000..4ce88e0 --- /dev/null +++ b/goson/goson.go @@ -0,0 +1,136 @@ +package goson + +/* + TODO: Better error handling +*/ + +import ( + "encoding/json" + "fmt" + "io/ioutil" + "os" + "os/user" + "path/filepath" +) + +const ( + defaultConfigPath = ".config" + defaultConfigFileName = "config.json" +) + +type Config struct { + AppName string + Loaded bool + Saved bool + Contents map[string]interface{} +} + +// Get the filepath for the config file +func (conf Config) FilePath() (fpath string, err error) { + u, err := user.Current() + if u != nil && err == nil { + fpath = filepath.Join(u.HomeDir, defaultConfigPath, conf.AppName, defaultConfigFileName) + } + return +} + +// Load configuration from filesystem +func (conf *Config) Load() { + conf.Contents = make(map[string]interface{}) + + confFilePath, err := conf.FilePath() + fileBody, err := ioutil.ReadFile(confFilePath) + if err != nil { + fmt.Println(err) + + } + + err = json.Unmarshal(fileBody, &conf.Contents) + if err != nil { + fmt.Println(err) + } + + conf.Loaded = true + conf.Saved = true +} + +// Retrieves Json data +func (conf Config) JsonData() ([]byte, error) { + return json.MarshalIndent(conf.Contents, "", " ") +} + +// Write config file back to filesystem +func (conf Config) Write() { + data, err := conf.JsonData() + confFilePath, err := conf.FilePath() + if err != nil { + fmt.Println(err) + return + } + + confDirname := filepath.Dir(confFilePath) + err = os.MkdirAll(confDirname, 0777) + if err != nil { + fmt.Println(err) + return + } + + err = ioutil.WriteFile(confFilePath, data, 0666) + if err != nil { + fmt.Println(err) + return + } + conf.Saved = true +} + +func (conf *Config) Clear() { + conf.Contents = make(map[string]interface{}) + conf.Saved = false +} + +// Gets a value from the config +func (conf Config) Get(key string) (interface{}, bool) { + v, ok := conf.Contents[key] + return v, ok +} + +// Gets a value from the config +func (conf Config) GetString(key string) (string, bool) { + v, ok := conf.Contents[key].(string) + return v, ok +} + +// Gets a value from the config +func (conf Config) GetInt(key string) (int, bool) { + v, ok := conf.Contents[key].(int) + return v, ok +} + +// Returns a list +func (conf Config) GetList(key string) (l []interface{}, ok bool) { + v, ok := conf.Get(key) + if ok { + l, ok = v.([]interface{}) + } + + return l, ok +} + +// Sets a value in the config +func (conf *Config) Set(key string, value interface{}) { + conf.Contents[key] = value + conf.Saved = false +} + +// Sets value and writes to file +func (conf *Config) SetAndWrite(key string, value interface{}) { + conf.Set(key, value) + conf.Write() +} + +// Load config for app name +func LoadConfig(appName string) (conf Config) { + conf.AppName = appName + conf.Load() + return conf +} diff --git a/pushbullet/pushbullet.go b/pushbullet/pushbullet.go new file mode 100644 index 0000000..7463c61 --- /dev/null +++ b/pushbullet/pushbullet.go @@ -0,0 +1,194 @@ +package pushbullet + +import ( + "bytes" + "encoding/json" + "fmt" + "io/ioutil" + "net/http" +) + +const ( + host = "https://api.pushbullet.com/v2" +) + +func New(apiKey string) PushBullet { + return PushBullet{apiKey: apiKey} +} + +type PushBullet struct { + apiKey string + client *http.Client + ActiveDevice Device + Devices []Device +} + +// Loads all devices for account into instance +func (pb *PushBullet) LoadDevices() []Device { + dl := new(DeviceList) + err := pb.pbRequest("GET", host+"/devices", nil, dl) + + if err != nil { + fmt.Println("error on pbRequest") + fmt.Println(err) + } + + pb.Devices = dl.Devices + + return dl.Devices +} + +// Lazy loaded version of LoadDevices +func (pb *PushBullet) GetDevices() []Device { + if len(pb.Devices) == 0 { + pb.LoadDevices() + } + + return pb.Devices +} + +func (pb PushBullet) PushNote(message string) { + body := map[string]interface{}{ + "type": "note", + "body": message, + } + + pb.Push(body) +} + +func (pb PushBullet) PushLink(title string, url string) { + pb.PushLinkWithBody(title, url, "") +} + +func (pb PushBullet) PushLinkWithBody(title string, url string, messBody string) { + body := map[string]interface{}{ + "type": "link", + "title": title, + "url": url, + "body": messBody, + } + + pb.Push(body) +} + +// Pushes a text message to active device +// TODO: handle response +func (pb PushBullet) Push(body map[string]interface{}) { + body["device_iden"] = pb.ActiveDevice.Iden + + result := new(interface{}) + pb.pbRequest("POST", host+"/pushes", body, result) +} + +// Sets active device by Nickname or Iden +func (pb *PushBullet) SetActiveDevice(key string) { + if len(pb.Devices) == 0 { + pb.LoadDevices() + } + + for _, d := range pb.Devices { + if d.Match(key) && d.CanPush() { + pb.ActiveDevice = d + } + } +} + +// Method for communicating with PushBullet +func (pb *PushBullet) pbRequest(method string, url string, body map[string]interface{}, result interface{}) error { + if pb.client == nil { + pb.client = &http.Client{} + } + + jsonBody, err := json.Marshal(body) + if err != nil { + fmt.Println("Error marshalling body") + fmt.Println(err) + } + + r, err := http.NewRequest(method, url, bytes.NewBuffer(jsonBody)) + if err != nil { + fmt.Println("Error on request create") + return err + } + + r.Header.Add("Content-Type", "application/json") + r.Header.Add("Application-Type", "application/json") + r.Header.Add("User-Agent", "gopush") + + r.SetBasicAuth(pb.apiKey, "") + + resp, err := pb.client.Do(r) + if err != nil { + fmt.Println("Error on request do") + fmt.Println(err) + return err + } + + defer resp.Body.Close() + responseBody, err := ioutil.ReadAll(resp.Body) + + if err != nil { + fmt.Println("Error on request read") + return err + } + err = json.Unmarshal(responseBody, result) + + return err +} + +// Response types + +type DeviceList struct { + Aliases []interface{} + Clients []interface{} + Devices []Device + Grants []interface{} + Pushes []interface{} +} + +type DeviceFingerprint struct { + mac_address string + android_id string +} + +type Device struct { + Iden string + Created float32 + Nickname string + Modified float32 + Push_token string + Fingerprint string + Active bool + Model string + App_version int32 + Type string + Kind string + Pushable bool + Manufacturer string +} + +// Returns Android Fingerprint +func (d Device) AndroidFingerprint() (DeviceFingerprint, error) { + fp := new(DeviceFingerprint) + err := json.Unmarshal([]byte(d.Fingerprint), fp) + return *fp, err +} + +// Returns if the device is available for pushing +func (d Device) CanPush() bool { + return d.Active && d.Pushable +} + +// Outputs the device in a friendly string format +func (d Device) Format() string { + return fmt.Sprintf("%s (%s)", d.Nickname, d.Kind) +} + +// Returns true if key matches Nickname or Iden +func (d Device) Match(key string) bool { + if d.Nickname == key || d.Iden == key { + return true + } + + return false +}