From 4c0f648d876098fb8ba2297e47fb46718588596b Mon Sep 17 00:00:00 2001 From: nsz Date: Tue, 15 Nov 2011 23:13:20 +0100 Subject: [PATCH] document renames and simplification --- document/document.go | 184 +++++++++++++++++++------------------- document/document_test.go | 20 ++--- 2 files changed, 103 insertions(+), 101 deletions(-) diff --git a/document/document.go b/document/document.go index c550619..1c61fcb 100644 --- a/document/document.go +++ b/document/document.go @@ -31,7 +31,7 @@ import ( const ClearSignedHeader = "-----BEGIN PGP SIGNED MESSAGE-----\n" -// (non-standard) MIME subtype for epoint documents, see RFC 2045 and RFC 2046 +// (non-standard) MIME type for epoint documents, see RFC 2045 and RFC 2046 var ContentType = map[string]string{ "cert": "text/plain.epoint.cert; charset=utf-8", "draft": "text/plain.epoint.draft; charset=utf-8", @@ -53,17 +53,17 @@ type Field struct { // Draft document represents an obligation transfer order type Draft struct { - Drawer string `marshal:"id"` // ID of the payer (signer of the document) - Beneficiary string `marshal:"id"` // ID of the payee - Amount int64 // amount transfered + Drawer string `marshal:"id"` + Beneficiary string `marshal:"id"` + Amount int64 Denomination string - IssueDate int64 `marshal:"date" key:"Issue-Date"` - // Draft is bounced before this date + Issuer string `marshal:"id"` + AuthorizedBy string `marshal:"id" key:"Authorized-By"` + Date int64 `marshal:"date"` MaturityDate int64 `marshal:"date" key:"Maturity-Date"` - Notes string // Arbitrary text notes of the drawer - Nonce string // unique number - Server string `marshal:"id"` // ID of the server - Drawee string `marshal:"id"` // ID of the obligation issuer + ExpiryDate int64 `marshal:"date" key:"Expiry-Date"` + Notes string + Nonce string // useful if more strict date of issue information is needed //References []string } @@ -72,36 +72,35 @@ type Draft struct { // References previous certificate (if any) // and the transfer related other documents type Cert struct { - Holder string `marshal:"id"` // ID of the creditor - Serial uint32 // serial number, number of certs of the holder - Date int64 `marshal:"date"` // date of issue - Balance int64 // current obligation value + Holder string `marshal:"id"` + Serial int64 + Date int64 `marshal:"date"` + Balance int64 Denomination string - Server string `marshal:"id"` // ID of the server - Issuer string `marshal:"id"` // ID of the obligation issuer (drawee?) - LastDebitSerial uint32 `key:"Last-Debit-Serial"` // serial of the last draft cert or 0 - LastCreditSerial uint32 `key:"Last-Credit-Serial"` // serial of the last credit cert or 0 - LastCert string `marshal:"id" key:"Last-Cert"` // ID of the previous cert if any - Difference int64 // difference from previous balance - Draft string `marshal:"id"` // draft ID related to the transfer - Drawer string `marshal:"id"` // ID of the drawer in the transaction - DrawerSerial uint32 `key:"Drawer-Serial"` // serial of the drawer's related debit cert - DrawerCert string `marshal:"id" key:"Drawer-Cert"` // ID of the drawer's related debit cert - Notes string // Arbitrary text notes of the server (signer) - References []string `marshal:"idlist"` // cert IDs for timestamping the system + Issuer string `marshal:"id"` + AuthorizedBy string `marshal:"id" key:"Authorized-By"` + LastDebitSerial int64 `key:"Last-Debit-Serial"` + LastCreditSerial int64 `key:"Last-Credit-Serial"` + LastCert string `marshal:"id" key:"Last-Cert"` + Difference int64 + Draft string `marshal:"id"` + Drawer string `marshal:"id"` + DrawerCert string `marshal:"id" key:"Drawer-Cert"` + Notes string // TODO: server or drawer? + References []string `marshal:"idlist"` } -func DecodeClearSigned(s []byte) (c *ClearSigned, err error) { +func ParseClearSigned(s []byte) (c *ClearSigned, err error) { hash, body, sig := split(s) if len(sig) == 0 { - err = fmt.Errorf("DecodeClearSigned could parse the signed document") + err = fmt.Errorf("ParseClearSigned could parse the signed document") return } c = &ClearSigned{string(hash), trimspace(dashunesc(body)), sig} return } -func EncodeClearSigned(c *ClearSigned) (data []byte, err error) { +func FormatClearSigned(c *ClearSigned) (data []byte, err error) { s := ClearSignedHeader if c.Hash != "" { s += "Hash: " + c.Hash + "\n" @@ -183,7 +182,7 @@ func parse(s []byte, doctype string) (v interface{}, err error) { } // TODO: limit errors -func render(v interface{}) ([]byte, error) { +func format(v interface{}) ([]byte, error) { doctype := "" switch v.(type) { case *Draft: @@ -210,8 +209,8 @@ func ParseDraft(s []byte) (draft *Draft, err error) { return } -func RenderDraft(draft *Draft) ([]byte, error) { - return render(draft) +func FormatDraft(draft *Draft) ([]byte, error) { + return format(draft) } func ParseCert(s []byte) (cert *Cert, err error) { @@ -223,33 +222,32 @@ func ParseCert(s []byte) (cert *Cert, err error) { return } -func RenderCert(cert *Cert) ([]byte, error) { - return render(cert) -} - -func formatId(s string) string { - return fmt.Sprintf("%040X", s) +func FormatCert(cert *Cert) ([]byte, error) { + return format(cert) } func parseId(s string) (string, error) { - dst := make([]byte, 20) if len(s) != 40 { return "", fmt.Errorf("parseId: expected 40 characters; got %d", len(s)) } + dst := make([]byte, len(s)/2) _, err := hex.Decode(dst, []byte(s)) - return string(dst), err + return s, err } -func quoteValue(s string) string { +func formatId(s string) string { return s } -func unquoteValue(s string) (string, error) { +func parseString(s string) (string, error) { + if len(s) > 140 { + return "", fmt.Errorf("parseString: 140 chars limit is exceeded") + } return s, nil } -func formatDate(i int64) string { - return time.SecondsToUTC(i).Format(time.RFC3339) +func formatString(s string) string { + return s } func parseDate(s string) (int64, error) { @@ -260,7 +258,11 @@ func parseDate(s string) (int64, error) { return t.Seconds(), nil } -func marshal(iv interface{}) []Field { +func formatDate(i int64) string { + return time.SecondsToUTC(i).Format(time.RFC3339) +} + +func unmarshal(fields []Field, iv interface{}) error { v := reflect.ValueOf(iv) if v.Kind() != reflect.Ptr || v.IsNil() || v.Elem().Kind() != reflect.Struct { panic("unmarshal: input is not a pointer to struct") @@ -268,7 +270,9 @@ func marshal(iv interface{}) []Field { v = v.Elem() t := v.Type() n := v.NumField() - fields := []Field{} + if len(fields) != n { + return fmt.Errorf("unmarshal: %s has %d fields, got %d\n", t.Name(), n, len(fields)) + } for i := 0; i < n; i++ { ft := t.Field(i) fv := v.Field(i) @@ -277,58 +281,73 @@ func marshal(iv interface{}) []Field { if k == "" { k = ft.Name } - val := "" + if fields[i].Key != k { + return fmt.Errorf("unmarshal: field %d of %s (%s) is missing\n", i+1, t.Name(), k) + } + s := fields[i].Value + var err error switch fv.Kind() { case reflect.String: + var val string switch m { case "id": - val = formatId(fv.String()) + val, err = parseId(s) case "": - val = quoteValue(fv.String()) + val, err = parseString(s) default: panic("bad string field tag") } + fv.SetString(val) case reflect.Int, reflect.Int32, reflect.Int64: + var val int64 switch m { case "date": - val = formatDate(fv.Int()) + val, err = parseDate(s) case "": - val = strconv.Itoa64(fv.Int()) + val, err = strconv.Atoi64(s) default: panic("bad int field tag") } + fv.SetInt(val) case reflect.Uint, reflect.Uint32, reflect.Uint64: + var val uint64 switch m { case "": - val = strconv.Uitoa64(fv.Uint()) + val, err = strconv.Atoui64(s) default: panic("bad uint field tag") } + fv.SetUint(val) case reflect.Slice: + var val []string switch m { case "idlist": if fv.Type().Elem().Kind() != reflect.String { panic("only string slice is supported") } - k := fv.Len() - for j := 0; j < k; j++ { - if j > 0 { - val += " " + ids := strings.Split(s, " ") + val = make([]string, len(ids)) + for j := range val { + val[j], err = parseId(ids[j]) + if err != nil { + return err } - val += formatId(fv.Index(j).String()) } default: panic("bad slice field tag") } + fv.Set(reflect.ValueOf(val)) default: panic("bad field type") } - fields = append(fields, Field{k, val}) + if err != nil { + return err + } } - return fields + return nil } -func unmarshal(fields []Field, iv interface{}) error { +func marshal(iv interface{}) []Field { v := reflect.ValueOf(iv) if v.Kind() != reflect.Ptr || v.IsNil() || v.Elem().Kind() != reflect.Struct { panic("unmarshal: input is not a pointer to struct") @@ -336,9 +355,7 @@ func unmarshal(fields []Field, iv interface{}) error { v = v.Elem() t := v.Type() n := v.NumField() - if len(fields) != n { - return fmt.Errorf("unmarshal: %s has %d fields, got %d\n", t.Name(), n, len(fields)) - } + fields := []Field{} for i := 0; i < n; i++ { ft := t.Field(i) fv := v.Field(i) @@ -347,70 +364,55 @@ func unmarshal(fields []Field, iv interface{}) error { if k == "" { k = ft.Name } - if fields[i].Key != k { - return fmt.Errorf("unmarshal: field %d of %s (%s) is missing\n", i, t.Name(), k) - } - s := fields[i].Value - var err error + val := "" switch fv.Kind() { case reflect.String: - var val string switch m { case "id": - val, err = parseId(s) + val = formatId(fv.String()) case "": - val, err = unquoteValue(s) + val = formatString(fv.String()) default: panic("bad string field tag") } - fv.SetString(val) case reflect.Int, reflect.Int32, reflect.Int64: - var val int64 switch m { case "date": - val, err = parseDate(s) + val = formatDate(fv.Int()) case "": - val, err = strconv.Atoi64(s) + val = strconv.Itoa64(fv.Int()) default: panic("bad int field tag") } - fv.SetInt(val) case reflect.Uint, reflect.Uint32, reflect.Uint64: - var val uint64 switch m { case "": - val, err = strconv.Atoui64(s) + val = strconv.Uitoa64(fv.Uint()) default: panic("bad uint field tag") } - fv.SetUint(val) case reflect.Slice: - var val []string switch m { case "idlist": if fv.Type().Elem().Kind() != reflect.String { panic("only string slice is supported") } - ids := strings.Split(s, " ") - val = make([]string, len(ids)) - for j := range val { - val[j], err = parseId(ids[j]) - if err != nil { - return err + k := fv.Len() + for j := 0; j < k; j++ { + if j > 0 { + val += " " } + val += formatId(fv.Index(j).String()) } default: panic("bad slice field tag") } - fv.Set(reflect.ValueOf(val)) default: panic("bad field type") } - if err != nil { - return err - } + fields = append(fields, Field{k, val}) } - return nil + return fields } func getLine(data []byte) (line, rest []byte) { diff --git a/document/document_test.go b/document/document_test.go index 72f907b..6113fac 100644 --- a/document/document_test.go +++ b/document/document_test.go @@ -95,7 +95,7 @@ func eqFields(f1, f2 []Field) bool { func TestClearSigned(t *testing.T) { for _, x := range testData { - c, err := DecodeClearSigned(x.D) + c, err := ParseClearSigned(x.D) if err != nil { t.Errorf("decoding %#v failed: %s\n", x.D, err) continue @@ -105,7 +105,7 @@ func TestClearSigned(t *testing.T) { } } for _, x := range testData { - d, err := EncodeClearSigned(x.C) + d, err := FormatClearSigned(x.C) if err != nil { t.Errorf("encoding %#v failed: %s\n", x.C, err) continue @@ -138,12 +138,13 @@ Drawer: 000000000000000000000000000000000000000A Beneficiary: 000000000000000000000000000000000000000B Amount: 1 Denomination: half euro -Issue-Date: 2011-11-13T12:20:35Z -Maturity-Date: 2011-12-27T09:18:46Z +Issuer: 000000000000000000000000000000000000000D +Authorized-By: 000000000000000000000000000000000000000C +Date: 2011-11-13T12:20:35Z +Maturity-Date: 2011-11-13T12:20:35Z +Expiry-Date: 2011-12-27T09:18:46Z Notes: some notes Nonce: 42 -Server: 000000000000000000000000000000000000000C -Drawee: 000000000000000000000000000000000000000D ` func TestDraft(t *testing.T) { @@ -152,7 +153,7 @@ func TestDraft(t *testing.T) { t.Errorf("ParseDraft failed: %s\n", err) return } - s, err := RenderDraft(d) + s, err := FormatDraft(d) if err != nil { t.Errorf("render %v draft failed: %s\n", d, err) } @@ -168,15 +169,14 @@ Serial: 13 Date: 2011-11-01T10:29:38Z Balance: 23 Denomination: half euro -Server: 000000000000000000000000000000000000000A Issuer: 000000000000000000000000000000000000000B +Authorized-By: 000000000000000000000000000000000000000A Last-Debit-Serial: 0 Last-Credit-Serial: 12 Last-Cert: 000000000000000000000000000000000000000C Difference: 1 Draft: 000000000000000000000000000000000000000D Drawer: 000000000000000000000000000000000000000E -Drawer-Serial: 2 Drawer-Cert: 000000000000000000000000000000000000000F Notes: - References: 000000000000000000000000000000000000000C 000000000000000000000000000000000000000F @@ -188,7 +188,7 @@ func TestCert(t *testing.T) { t.Errorf("ParseCert failed: %s\n", err) return } - s, err := RenderCert(c) + s, err := FormatCert(c) if err != nil { t.Errorf("render %v cert failed: %s\n", c, err) } -- 2.20.1