Add Type() to Message interface, check types when marshalling requests

This commit is contained in:
Aaron Lindsay 2017-03-31 09:25:07 -04:00
parent 85684883c6
commit d822179446
8 changed files with 170 additions and 11 deletions

View File

@ -28,6 +28,10 @@ func (r *StatementRequest) Valid() (bool, error) {
return true, nil
}
func (r *StatementRequest) Type() messageType {
return BankRq
}
type Payee struct {
XMLName xml.Name `xml:"PAYEE"`
Name String `xml:"NAME"`
@ -155,6 +159,10 @@ func (sr StatementResponse) Valid() (bool, error) {
return true, nil
}
func (sr StatementResponse) Type() messageType {
return BankRs
}
func decodeBankingMessageSet(d *xml.Decoder, start xml.StartElement) ([]Message, error) {
var msgs []Message
for {

108
common.go
View File

@ -5,11 +5,115 @@ import (
"github.com/aclindsa/go/src/encoding/xml"
)
// Represents a top-level OFX message set (i.e. BANKMSGSRSV1)
// Represents an OFX message in a message set
type Message interface {
Name() string // The name of the OFX element this set represents
Name() string // The name of the OFX transaction wrapper element this represents
Valid() (bool, error) // Called before a Message is marshaled and after
// it's unmarshaled to ensure the request or response is valid
Type() messageType // The message set this message belongs to
}
type messageType uint
const (
// Requests
SignonRq messageType = iota
SignupRq
BankRq
CreditCardRq
LoanRq
InvStmtRq
InterXferRq
WireXferRq
BillpayRq
EmailRq
SecListRq
PresDirRq
PresDlvRq
ProfileRq
ImageRq
// Responses
SignonRs
SignupRs
BankRs
CreditCardRs
LoanRs
InvStmtRs
InterXferRs
WireXferRs
BillpayRs
EmailRs
SecListRs
PresDirRs
PresDlvRs
ProfileRs
ImageRs
)
func (t messageType) String() string {
switch t {
case SignonRq:
return "SIGNONMSGSRQV1"
case SignupRq:
return "SIGNUPMSGSRQV1"
case BankRq:
return "BANKMSGSRQV1"
case CreditCardRq:
return "CREDITCARDMSGSRQV1"
case LoanRq:
return "LOANMSGSRQV1"
case InvStmtRq:
return "INVSTMTMSGSRQV1"
case InterXferRq:
return "INTERXFERMSGSRQV1"
case WireXferRq:
return "WIREXFERMSGSRQV1"
case BillpayRq:
return "BILLPAYMSGSRQV1"
case EmailRq:
return "EMAILMSGSRQV1"
case SecListRq:
return "SECLISTMSGSRQV1"
case PresDirRq:
return "PRESDIRMSGSRQV1"
case PresDlvRq:
return "PRESDLVMSGSRQV1"
case ProfileRq:
return "PROFMSGSRQV1"
case ImageRq:
return "IMAGEMSGSRQV1"
case SignonRs:
return "SIGNONMSGSRSV1"
case SignupRs:
return "SIGNUPMSGSRSV1"
case BankRs:
return "BANKMSGSRSV1"
case CreditCardRs:
return "CREDITCARDMSGSRSV1"
case LoanRs:
return "LOANMSGSRSV1"
case InvStmtRs:
return "INVSTMTMSGSRSV1"
case InterXferRs:
return "INTERXFERMSGSRSV1"
case WireXferRs:
return "WIREXFERMSGSRSV1"
case BillpayRs:
return "BILLPAYMSGSRSV1"
case EmailRs:
return "EMAILMSGSRSV1"
case SecListRs:
return "SECLISTMSGSRSV1"
case PresDirRs:
return "PRESDIRMSGSRSV1"
case PresDlvRs:
return "PRESDLVMSGSRSV1"
case ProfileRs:
return "PROFMSGSRSV1"
case ImageRs:
return "IMAGEMSGSRSV1"
}
panic("Invalid messageType")
}
// Map of error codes to their meanings, SEVERITY, and conditions under which

View File

@ -28,6 +28,10 @@ func (r *CCStatementRequest) Valid() (bool, error) {
return true, nil
}
func (r *CCStatementRequest) Type() messageType {
return CreditCardRq
}
type CCStatementResponse struct {
XMLName xml.Name `xml:"CCSTMTTRNRS"`
TrnUID UID `xml:"TRNUID"`
@ -62,6 +66,10 @@ func (sr CCStatementResponse) Valid() (bool, error) {
return true, nil
}
func (sr CCStatementResponse) Type() messageType {
return CreditCardRs
}
func decodeCCMessageSet(d *xml.Decoder, start xml.StartElement) ([]Message, error) {
var msgs []Message
for {

View File

@ -33,6 +33,10 @@ func (r *InvStatementRequest) Valid() (bool, error) {
return true, nil
}
func (r *InvStatementRequest) Type() messageType {
return InvStmtRq
}
type InvTran struct {
XMLName xml.Name `xml:"INVTRAN"`
FiTId String `xml:"FITID"`
@ -816,6 +820,10 @@ func (sr InvStatementResponse) Valid() (bool, error) {
return true, nil
}
func (sr InvStatementResponse) Type() messageType {
return InvStmtRs
}
func decodeInvestmentsMessageSet(d *xml.Decoder, start xml.StartElement) ([]Message, error) {
var msgs []Message
for {

View File

@ -25,6 +25,10 @@ func (r *ProfileRequest) Valid() (bool, error) {
return true, nil
}
func (r *ProfileRequest) Type() messageType {
return ProfileRq
}
type SignonInfo struct {
XMLName xml.Name `xml:"SIGNONINFO"`
SignonRealm String `xml:"SIGNONREALM"`
@ -130,6 +134,10 @@ func (pr ProfileResponse) Valid() (bool, error) {
return true, nil
}
func (pr ProfileResponse) Type() messageType {
return ProfileRs
}
func decodeProfileMessageSet(d *xml.Decoder, start xml.StartElement) ([]Message, error) {
var msgs []Message
for {

View File

@ -29,14 +29,17 @@ type Request struct {
indent bool // Whether to indent the marshaled XML
}
func marshalMessageSet(e *xml.Encoder, requests []Message, setname string) error {
func marshalMessageSet(e *xml.Encoder, requests []Message, set messageType) error {
if len(requests) > 0 {
messageSetElement := xml.StartElement{Name: xml.Name{Local: setname}}
messageSetElement := xml.StartElement{Name: xml.Name{Local: set.String()}}
if err := e.EncodeToken(messageSetElement); err != nil {
return err
}
for _, request := range requests {
if request.Type() != set {
return errors.New("Expected " + set.String() + " message , found " + request.Type().String())
}
if ok, err := request.Valid(); !ok {
return err
}
@ -104,7 +107,7 @@ NEWFILEUID:NONE
if ok, err := oq.Signon.Valid(); !ok {
return nil, err
}
signonMsgSet := xml.StartElement{Name: xml.Name{Local: "SIGNONMSGSRQV1"}}
signonMsgSet := xml.StartElement{Name: xml.Name{Local: SignonRq.String()}}
if err := encoder.EncodeToken(signonMsgSet); err != nil {
return nil, err
}
@ -115,22 +118,22 @@ NEWFILEUID:NONE
return nil, err
}
if err := marshalMessageSet(encoder, oq.Signup, "SIGNUPMSGSRQV1"); err != nil {
if err := marshalMessageSet(encoder, oq.Signup, SignupRq); err != nil {
return nil, err
}
if err := marshalMessageSet(encoder, oq.Banking, "BANKMSGSRQV1"); err != nil {
if err := marshalMessageSet(encoder, oq.Banking, BankRq); err != nil {
return nil, err
}
if err := marshalMessageSet(encoder, oq.CreditCards, "CREDITCARDMSGSRQV1"); err != nil {
if err := marshalMessageSet(encoder, oq.CreditCards, CreditCardRq); err != nil {
return nil, err
}
if err := marshalMessageSet(encoder, oq.Investments, "INVSTMTMSGSRQV1"); err != nil {
if err := marshalMessageSet(encoder, oq.Investments, InvStmtRq); err != nil {
return nil, err
}
if err := marshalMessageSet(encoder, oq.Securities, "SECLISTMSGSRQV1"); err != nil {
if err := marshalMessageSet(encoder, oq.Securities, SecListRq); err != nil {
return nil, err
}
if err := marshalMessageSet(encoder, oq.Profile, "PROFMSGSRQV1"); err != nil {
if err := marshalMessageSet(encoder, oq.Profile, ProfileRq); err != nil {
return nil, err
}

View File

@ -37,6 +37,10 @@ func (r *SecListRequest) Valid() (bool, error) {
return true, nil
}
func (r *SecListRequest) Type() messageType {
return SecListRq
}
type SecListResponse struct {
XMLName xml.Name `xml:"SECLISTTRNRS"`
TrnUID UID `xml:"TRNUID"`
@ -55,6 +59,10 @@ func (r SecListResponse) Valid() (bool, error) {
return true, nil
}
func (r SecListResponse) Type() messageType {
return SecListRs
}
type Security interface {
SecurityType() string
}
@ -176,6 +184,10 @@ func (r SecurityList) Valid() (bool, error) {
return true, nil
}
func (r SecurityList) Type() messageType {
return SecListRs
}
func (r *SecurityList) UnmarshalXML(d *xml.Decoder, start xml.StartElement) error {
for {
tok, err := nextNonWhitespaceToken(d)

View File

@ -24,6 +24,10 @@ func (r *AcctInfoRequest) Valid() (bool, error) {
return true, nil
}
func (r *AcctInfoRequest) Type() messageType {
return SignupRq
}
type HolderInfo struct {
XMLName xml.Name
FirstName String `xml:"FIRSTNAME"`
@ -125,6 +129,10 @@ func (air AcctInfoResponse) Valid() (bool, error) {
return true, nil
}
func (air AcctInfoResponse) Type() messageType {
return SignupRs
}
func decodeSignupMessageSet(d *xml.Decoder, start xml.StartElement) ([]Message, error) {
var msgs []Message
for {