From 3d38e413ce8cd0ee2fa78571e1cf72972cf2c977 Mon Sep 17 00:00:00 2001 From: bigeagle Date: Fri, 15 Apr 2016 00:47:50 +0800 Subject: [PATCH] feature: syncing status --- .testpackages.txt | 1 + internal/status/status.go | 144 +++++++++++++++++++++++++++++++++ internal/status/status_test.go | 39 +++++++++ 3 files changed, 184 insertions(+) create mode 100644 internal/status/status.go create mode 100644 internal/status/status_test.go diff --git a/.testpackages.txt b/.testpackages.txt index ba04577..9e724cc 100644 --- a/.testpackages.txt +++ b/.testpackages.txt @@ -1,2 +1,3 @@ github.com/tuna/tunasync/internal +github.com/tuna/tunasync/internal/status github.com/tuna/tunasync/manager diff --git a/internal/status/status.go b/internal/status/status.go new file mode 100644 index 0000000..dfab49c --- /dev/null +++ b/internal/status/status.go @@ -0,0 +1,144 @@ +package status + +import ( + "encoding/json" + "errors" + "fmt" + "strconv" + "strings" + "time" +) + +type syncStatus uint8 + +const ( + None syncStatus = iota + Failed + Success + Syncing + PreSyncing + Paused + Disabled +) + +type MirrorStatus struct { + Name string + Status syncStatus + LastUpdate time.Time + Upstream string + Size string // approximate size +} + +func (s MirrorStatus) MarshalJSON() ([]byte, error) { + m := map[string]interface{}{ + "name": s.Name, + "status": s.Status, + "last_update": s.LastUpdate.Format("2006-01-02 15:04:05"), + "last_update_ts": fmt.Sprintf("%d", s.LastUpdate.Unix()), + "size": s.Size, + "upstream": s.Upstream, + } + return json.Marshal(m) +} + +func (s *MirrorStatus) UnmarshalJSON(v []byte) error { + var m map[string]interface{} + + err := json.Unmarshal(v, &m) + if err != nil { + return err + } + + if name, ok := m["name"]; ok { + if s.Name, ok = name.(string); !ok { + return errors.New("name should be a string") + } + } else { + return errors.New("key `name` does not exist in the json") + } + if upstream, ok := m["upstream"]; ok { + if s.Upstream, ok = upstream.(string); !ok { + return errors.New("upstream should be a string") + } + } else { + return errors.New("key `upstream` does not exist in the json") + } + if size, ok := m["size"]; ok { + if s.Size, ok = size.(string); !ok { + return errors.New("size should be a string") + } + } else { + return errors.New("key `size` does not exist in the json") + } + // tricky: status + if status, ok := m["status"]; ok { + if ss, ok := status.(string); ok { + err := json.Unmarshal([]byte(`"`+ss+`"`), &(s.Status)) + if err != nil { + return err + } + } else { + return errors.New("status should be a string") + } + } else { + return errors.New("key `status` does not exist in the json") + } + // tricky: last update + if lastUpdate, ok := m["last_update_ts"]; ok { + if sts, ok := lastUpdate.(string); ok { + ts, err := strconv.Atoi(sts) + if err != nil { + return fmt.Errorf("last_update_ts should be a interger, got: %s", sts) + } + s.LastUpdate = time.Unix(int64(ts), 0) + } else { + return fmt.Errorf("last_update_ts should be a string of integer, got: %s", lastUpdate) + } + } else { + return errors.New("key `last_update_ts` does not exist in the json") + } + return nil +} + +func (s syncStatus) MarshalJSON() ([]byte, error) { + var strStatus string + switch s { + case None: + strStatus = "none" + case Success: + strStatus = "success" + case Syncing: + strStatus = "syncing" + case PreSyncing: + strStatus = "pre-syncing" + case Paused: + strStatus = "paused" + case Disabled: + strStatus = "disabled" + default: + return []byte{}, errors.New("Invalid status value") + } + + return json.Marshal(strStatus) +} + +func (s *syncStatus) UnmarshalJSON(v []byte) error { + sv := strings.Trim(string(v), `"`) + switch sv { + case "none": + *s = None + case "success": + *s = Success + case "syncing": + *s = Syncing + case "pre-syncing": + *s = PreSyncing + case "paused": + *s = Paused + case "disabled": + *s = Disabled + default: + return fmt.Errorf("Invalid status value: %s", string(v)) + } + return nil +} diff --git a/internal/status/status_test.go b/internal/status/status_test.go new file mode 100644 index 0000000..578a115 --- /dev/null +++ b/internal/status/status_test.go @@ -0,0 +1,39 @@ +package status + +import ( + "encoding/json" + "testing" + "time" + + . "github.com/smartystreets/goconvey/convey" +) + +func TestStatus(t *testing.T) { + Convey("status json ser-de should work", t, func() { + tz := "Asia/Shanghai" + loc, err := time.LoadLocation(tz) + So(err, ShouldBeNil) + + m := MirrorStatus{ + Name: "tunalinux", + Status: Success, + LastUpdate: time.Date(2016, time.April, 16, 23, 8, 10, 0, loc), + Size: "5GB", + Upstream: "rsync://mirrors.tuna.tsinghua.edu.cn/tunalinux/", + } + + b, err := json.Marshal(m) + So(err, ShouldBeNil) + // fmt.Println(string(b)) + var m2 MirrorStatus + err = json.Unmarshal(b, &m2) + So(err, ShouldBeNil) + // fmt.Printf("%#v", m2) + So(m2.Name, ShouldEqual, m.Name) + So(m2.Status, ShouldEqual, m.Status) + So(m2.LastUpdate.Unix(), ShouldEqual, m.LastUpdate.Unix()) + So(m2.LastUpdate.UnixNano(), ShouldEqual, m.LastUpdate.UnixNano()) + So(m2.Size, ShouldEqual, m.Size) + So(m2.Upstream, ShouldEqual, m.Upstream) + }) +}