Initial but not really

This commit is contained in:
Bel LaPointe
2019-02-26 17:56:07 -07:00
commit c8318d45ac
16 changed files with 771 additions and 0 deletions

23
mytinytodo/buffer.go Normal file
View File

@@ -0,0 +1,23 @@
package mytinytodo
import (
"local/mytinytodoclient/mytinytodo/remote"
"local/rproxy3/storage"
)
type Buffer struct {
remote *remote.Client
db storage.DB
}
func NewBuffer(config *remote.Config) (*Buffer, error) {
remote, err := remote.NewClient(config)
if err != nil {
return nil, err
}
db := storage.NewMap()
return &Buffer{
remote: remote,
db: db,
}, nil
}

7
mytinytodo/config.go Normal file
View File

@@ -0,0 +1,7 @@
package mytinytodo
import "local/mytinytodoclient/mytinytodo/remote"
func NewConfig() (*remote.Config, error) {
return remote.NewConfig()
}

140
mytinytodo/remote/client.go Normal file
View File

@@ -0,0 +1,140 @@
package remote
import (
"encoding/json"
"fmt"
"log"
"net/http"
"net/url"
)
type Client struct {
config *Config
http *http.Client
session *http.Cookie
}
func NewClient(config *Config) (*Client, error) {
return &Client{
config: config,
}, nil
}
func (c *Client) ParseArgs() error {
for i := 0; i < len(c.config.args); i++ {
arg := c.config.args[i]
switch arg {
case "list":
log.Printf("lists: %v", fmt.Sprint(c.Lists()))
case "tasks":
listID := c.config.args[i+1]
i += 1
log.Printf("tasks: %v", fmt.Sprint(c.Tasks(List{ID: listID})))
case "new":
listID := c.config.args[i+1]
i += 1
taskTitle := c.config.args[i+1]
i += 1
tagsCSV := c.config.args[i+1]
i += 1
log.Printf("new: %v", fmt.Sprint(c.NewTask(List{ID: listID}, Task{Title: taskTitle}, tagsCSV)))
case "close":
taskID := c.config.args[i+1]
i += 1
log.Printf("close: %v", fmt.Sprint(c.CloseTask(Task{ID: taskID})))
case "open":
taskID := c.config.args[i+1]
i += 1
log.Printf("open: %v", fmt.Sprint(c.OpenTask(Task{ID: taskID})))
default:
log.Printf("unknown arg %q", arg)
}
}
return nil
}
func (c *Client) Lists() ([]List, error) {
client, err := NewHTTP(c.config.remote, c.config.password)
if err != nil {
return nil, err
}
var lists loadListsResponse
if resp, err := client.Get("ajax.php?loadLists"); err != nil {
return nil, err
} else if err := json.NewDecoder(resp.Body).Decode(&lists); err != nil {
return nil, fmt.Errorf("cannot read lists: %v", err)
}
return lists.Lists, nil
}
func (c *Client) Tasks(list List) ([]Task, error) {
client, err := NewHTTP(c.config.remote, c.config.password)
if err != nil {
return nil, err
}
var tasks loadTasksResponse
if resp, err := client.Get("ajax.php?loadTasks&list=" + list.ID); err != nil {
return nil, err
} else if err := json.NewDecoder(resp.Body).Decode(&tasks); err != nil {
return nil, fmt.Errorf("cannot read tasks: %v", err)
}
return tasks.Tasks, nil
}
func (c *Client) NewTask(list List, task Task, tags string) error {
log.Printf("new: %v < %v", list, task.Title)
client, err := NewHTTP(c.config.remote, c.config.password)
if err != nil {
return err
}
form := url.Values{}
form.Add("list", list.ID)
form.Add("title", task.Title)
form.Add("tag", "/"+tags+"/")
var lists loadListsResponse
if resp, err := client.Post("ajax.php?newTask", form.Encode()); err != nil {
return err
} else if err := json.NewDecoder(resp.Body).Decode(&lists); err != nil {
return fmt.Errorf("cannot make task: %v", err)
}
log.Print(lists)
return nil
}
func (c *Client) CloseTask(task Task) error {
log.Printf("close: %v", task.ID)
client, err := NewHTTP(c.config.remote, c.config.password)
if err != nil {
return err
}
form := url.Values{}
form.Add("id", task.ID)
form.Add("compl", "1")
var lists loadListsResponse
if resp, err := client.Post("ajax.php?completeTask="+task.ID, form.Encode()); err != nil {
return err
} else if err := json.NewDecoder(resp.Body).Decode(&lists); err != nil {
return fmt.Errorf("cannot close task: %v", err)
}
log.Print(lists)
return nil
}
func (c *Client) OpenTask(task Task) error {
log.Printf("open: %v", task.ID)
client, err := NewHTTP(c.config.remote, c.config.password)
if err != nil {
return err
}
form := url.Values{}
form.Add("id", task.ID)
form.Add("compl", "0")
var lists loadListsResponse
if resp, err := client.Post("ajax.php?completeTask="+task.ID, form.Encode()); err != nil {
return err
} else if err := json.NewDecoder(resp.Body).Decode(&lists); err != nil {
return fmt.Errorf("cannot close task: %v", err)
}
log.Print(lists)
return nil
}

View File

@@ -0,0 +1,51 @@
package remote
import (
"flag"
"os"
)
type Config struct {
remote string
password string
args []string
}
var globalConfig *Config
func NewConfig() (*Config, error) {
globalConfig = &Config{}
if err := globalConfig.fromEnv(); err != nil {
return nil, err
}
if err := globalConfig.fromFlags(); err != nil {
return nil, err
}
return globalConfig, nil
}
func (c *Config) fromFlags() error {
fs := flag.NewFlagSet(os.Args[0], flag.ExitOnError)
remote := fs.String("remote", "https://todo.home.blapointe.com", "remote mytinytodo")
password := fs.String("p", "", "mytinytodo password")
if err := fs.Parse(os.Args[1:]); err != nil {
panic(err)
}
c.remote = *remote
c.password = *password
c.args = fs.Args()
return nil
}
func (c *Config) fromEnv() error {
return nil
}
func getEnvOrDefault(key, def string) string {
if v, ok := os.LookupEnv(key); ok {
return v
}
return def
}

99
mytinytodo/remote/http.go Normal file
View File

@@ -0,0 +1,99 @@
package remote
import (
"fmt"
"io"
"io/ioutil"
"net/http"
"net/http/cookiejar"
"net/url"
"strings"
)
type HTTP struct {
client *http.Client
domain string
password string
}
func NewHTTP(domain, password string) (*HTTP, error) {
j, _ := cookiejar.New(nil)
//Transport: &http.Transport{Proxy: http.ProxyURL(&url.URL{
// Host: "localhost:8890",
// Scheme: "http",
//})},
h := &HTTP{
client: &http.Client{
Jar: j,
},
domain: domain,
password: password,
}
if resp, err := h.Get("/"); err != nil {
return nil, err
} else if resp.StatusCode != 200 {
return nil, fmt.Errorf("bad status from endpoint: %v", resp.StatusCode)
}
if password != "" {
form := url.Values{}
form.Add("login", "1")
form.Add("password", password)
if resp, err := h.Post("ajax.php?login", form.Encode()); err != nil {
return nil, err
} else if b, _ := ioutil.ReadAll(resp.Body); string(b) == `{"logged":0}` {
return nil, fmt.Errorf("bad password")
} else if string(b) != `{"logged":1}` {
return nil, fmt.Errorf("bad login: %q", b)
}
if resp, err := h.Get("/"); err != nil {
return nil, err
} else if resp.StatusCode != 200 {
return nil, fmt.Errorf("bad status from endpoint: %v", resp.StatusCode)
}
}
return h, nil
}
func (h *HTTP) Get(path string) (*http.Response, error) {
req, err := h.NewReq("GET", path)
if err != nil {
return nil, err
}
return h.Do(req)
}
func (h *HTTP) Post(path, body string) (*http.Response, error) {
req, err := h.NewReq("POST", path, body)
if err != nil {
return nil, err
}
return h.Do(req)
}
func (h *HTTP) Do(req *http.Request) (*http.Response, error) {
resp, err := h.client.Do(req)
if err != nil {
return nil, err
}
return resp, nil
}
func (h *HTTP) NewReq(method string, pathAndBody ...string) (*http.Request, error) {
path := ""
var bodyReader io.Reader
if len(pathAndBody) > 0 {
path = pathAndBody[0]
}
if !strings.HasPrefix(path, "/") {
path = "/" + path
}
if len(pathAndBody) > 1 {
bodyReader = strings.NewReader(pathAndBody[1])
}
r, err := http.NewRequest(method, h.domain+path, bodyReader)
if err != nil {
return nil, err
}
r.Header.Add("Content-Type", "application/x-www-form-urlencoded")
return r, nil
}

11
mytinytodo/remote/list.go Normal file
View File

@@ -0,0 +1,11 @@
package remote
type loadListsResponse struct {
Total int `json:"total"`
Lists []List `json:"list"`
}
type List struct {
ID string `json:"id"`
Name string `json:"name"`
}

12
mytinytodo/remote/task.go Normal file
View File

@@ -0,0 +1,12 @@
package remote
type loadTasksResponse struct {
Total int `json:"total"`
Tasks []Task `json:"list"`
}
type Task struct {
ID string `json:"id"`
Title string `json:"title"`
Complete int `json:"compl"`
}