This commit is contained in:
ViViDboarder 2014-09-19 18:32:10 -07:00
commit 9df272c07c
3 changed files with 433 additions and 0 deletions

103
gopush.go Normal file
View File

@ -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())
}
}

136
goson/goson.go Normal file
View File

@ -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
}

194
pushbullet/pushbullet.go Normal file
View File

@ -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
}