diff --git a/src/banktransfer/Dockerfile b/src/banktransfer/Dockerfile new file mode 100644 index 0000000000000000000000000000000000000000..a40980b75076e2bcce0ce98cb3d4ff8f3d4e28fe --- /dev/null +++ b/src/banktransfer/Dockerfile @@ -0,0 +1,17 @@ +FROM golang:1.16-buster + +WORKDIR /go/src/app +COPY ./banktransfer . + +RUN apt update +RUN apt install -y protobuf-compiler +RUN go install google.golang.org/protobuf/cmd/protoc-gen-go@v1.28 +RUN go install google.golang.org/grpc/cmd/protoc-gen-go-grpc@1.2 + +RUN go mod download +RUN go generate ./... +RUN go install + +CMD ["banktransfer"] + +EXPOSE 9111 \ No newline at end of file diff --git a/src/banktransfer/go.mod b/src/banktransfer/go.mod index b6bac315ce032a6a4ab8812d0cf3a802da84f284..cd0ad4ec63ccfb3cf80760022adbca5915322a26 100644 --- a/src/banktransfer/go.mod +++ b/src/banktransfer/go.mod @@ -3,11 +3,15 @@ module gitlab.reutlingen-university.de/albrecht/myaktion-go/src/banktransfer go 1.20 require ( - github.com/golang/protobuf v1.5.3 // indirect + github.com/golang/protobuf v1.5.3 + github.com/sirupsen/logrus v1.9.3 + google.golang.org/grpc v1.55.0 + google.golang.org/protobuf v1.30.0 +) + +require ( golang.org/x/net v0.8.0 // indirect golang.org/x/sys v0.6.0 // indirect golang.org/x/text v0.8.0 // indirect google.golang.org/genproto v0.0.0-20230306155012-7f2fa6fef1f4 // indirect - google.golang.org/grpc v1.55.0 // indirect - google.golang.org/protobuf v1.30.0 // indirect ) diff --git a/src/banktransfer/go.sum b/src/banktransfer/go.sum index 3bedd45bde1984edbcf09c83e9925b9f7bb3b5c8..4367155d74fb46316a881782b9aeb58be21d8c10 100644 --- a/src/banktransfer/go.sum +++ b/src/banktransfer/go.sum @@ -1,9 +1,21 @@ +github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= +github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk= github.com/golang/protobuf v1.5.3 h1:KhyjKVUg7Usr/dYsdSqoFveMYd5ko72D+zANwlG1mmg= github.com/golang/protobuf v1.5.3/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY= github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38= +github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= +github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/sirupsen/logrus v1.9.3 h1:dueUQJ1C2q9oE3F7wvmSGAaVtTmUizReu6fjN8uqzbQ= +github.com/sirupsen/logrus v1.9.3/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ= +github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/testify v1.7.0 h1:nwc3DEeHmmLAfoZucVR881uASk0Mfjw8xYJ99tb5CcY= +github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= golang.org/x/net v0.8.0 h1:Zrh2ngAOFYneWTAIAPethzeaQLuHwhuBkuV6ZiRnUaQ= golang.org/x/net v0.8.0/go.mod h1:QVkue5JL9kW//ek3r6jTKnTFis1tRmNAW2P1shuFdJc= +golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.6.0 h1:MVltZSvRTcU2ljQOhs94SXPftV6DCNnZViHeQps87pQ= golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/text v0.8.0 h1:57P1ETyNKtuIjB4SRd15iJxuhj8Gc416Y78H3qgMh68= @@ -17,3 +29,6 @@ google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp0 google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= google.golang.org/protobuf v1.30.0 h1:kPPoIgf3TsEvrm0PFe15JQ+570QVxYzEvvHqChK+cng= google.golang.org/protobuf v1.30.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I= +gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c h1:dUUwHk2QECo/6vqA44rthZ8ie2QXMNeKRTHCNY2nXvo= +gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= diff --git a/src/myaktion/Dockerfile b/src/myaktion/Dockerfile index d8022da86249db01e38769a8580b650fc25de8f5..77cd25e5be5b0c9d45c69ab5110677fb995ca28a 100644 --- a/src/myaktion/Dockerfile +++ b/src/myaktion/Dockerfile @@ -1,9 +1,18 @@ -FROM golang:1.20-buster +FROM golang:1.16-buster +# non-go modules dependencies +RUN apt update +RUN apt install -y protobuf-compiler +RUN go install google.golang.org/protobuf/cmd/protoc-gen-go@v1.28 +RUN go install google.golang.org/grpc/cmd/protoc-gen-go-grpc@1.2 +# copy code and protobuf WORKDIR /go/src/app -COPY . . +COPY ./myaktion . +COPY ./banktransfer/grpc/banktransfer/banktransfer.proto ./client/banktransfer/ RUN go mod download +RUN go generate ./... RUN go install +RUN wget https://raw.githubusercontent.com/vishnubob/wait-for-it/81b1373f17855a4dc21156cfe1694c31d7d1792e/wait-for-it.sh RUN chmod +x ./wait-for-it.sh ./docker-entrypoint.sh ENTRYPOINT ["./docker-entrypoint.sh"] CMD ["myaktion"] -EXPOSE 8000 +EXPOSE 8000 \ No newline at end of file diff --git a/src/myaktion/client/banktransfer.go b/src/myaktion/client/banktransfer.go new file mode 100644 index 0000000000000000000000000000000000000000..0b684be231a6b6dcd76d8a0e9580d0a2ad9f1acc --- /dev/null +++ b/src/myaktion/client/banktransfer.go @@ -0,0 +1,29 @@ +package client + +import ( + "context" + "os" + "time" + + log "github.com/sirupsen/logrus" + "google.golang.org/grpc" +) + +var ( + TimeoutLimitation = time.Second * 10 + bankTransferTarget = os.Getenv("BANKTRANSFER_CONNECT") +) + +func GetBankTransferConnection() (*grpc.ClientConn, error) { + var err error + log.WithFields(log.Fields{ + "target": bankTransferTarget, + }).Infoln("Connecting to banktransfer service") + var conn *grpc.ClientConn + ctx, _ := context.WithTimeout(context.Background(), TimeoutLimitation) + conn, err = grpc.DialContext(ctx, bankTransferTarget, grpc.WithInsecure(), grpc.WithBlock()) + if err != nil { + return nil, err + } + return conn, nil +} diff --git a/src/myaktion/client/banktransfer/banktransfer.pb.go b/src/myaktion/client/banktransfer/banktransfer.pb.go new file mode 100644 index 0000000000000000000000000000000000000000..0fe9fbc77f00a2edf90e32dffd7f2feb427f15c4 --- /dev/null +++ b/src/myaktion/client/banktransfer/banktransfer.pb.go @@ -0,0 +1,365 @@ +// Code generated by protoc-gen-go. DO NOT EDIT. +// versions: +// protoc-gen-go v1.30.0 +// protoc v3.12.4 +// source: banktransfer/banktransfer.proto + +package banktransfer + +import ( + empty "github.com/golang/protobuf/ptypes/empty" + protoreflect "google.golang.org/protobuf/reflect/protoreflect" + protoimpl "google.golang.org/protobuf/runtime/protoimpl" + reflect "reflect" + sync "sync" +) + +const ( + // Verify that this generated code is sufficiently up-to-date. + _ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion) + // Verify that runtime/protoimpl is sufficiently up-to-date. + _ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20) +) + +type Account struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Name string `protobuf:"bytes,1,opt,name=name,proto3" json:"name,omitempty"` + BankName string `protobuf:"bytes,2,opt,name=bank_name,json=bankName,proto3" json:"bank_name,omitempty"` + Number string `protobuf:"bytes,3,opt,name=number,proto3" json:"number,omitempty"` +} + +func (x *Account) Reset() { + *x = Account{} + if protoimpl.UnsafeEnabled { + mi := &file_banktransfer_banktransfer_proto_msgTypes[0] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *Account) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*Account) ProtoMessage() {} + +func (x *Account) ProtoReflect() protoreflect.Message { + mi := &file_banktransfer_banktransfer_proto_msgTypes[0] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use Account.ProtoReflect.Descriptor instead. +func (*Account) Descriptor() ([]byte, []int) { + return file_banktransfer_banktransfer_proto_rawDescGZIP(), []int{0} +} + +func (x *Account) GetName() string { + if x != nil { + return x.Name + } + return "" +} + +func (x *Account) GetBankName() string { + if x != nil { + return x.BankName + } + return "" +} + +func (x *Account) GetNumber() string { + if x != nil { + return x.Number + } + return "" +} + +type Transaction struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Id int32 `protobuf:"varint,1,opt,name=id,proto3" json:"id,omitempty"` + DonationId int32 `protobuf:"varint,2,opt,name=donation_id,json=donationId,proto3" json:"donation_id,omitempty"` + Amount float32 `protobuf:"fixed32,3,opt,name=amount,proto3" json:"amount,omitempty"` + Reference string `protobuf:"bytes,4,opt,name=reference,proto3" json:"reference,omitempty"` + FromAccount *Account `protobuf:"bytes,5,opt,name=from_account,json=fromAccount,proto3" json:"from_account,omitempty"` + ToAccount *Account `protobuf:"bytes,6,opt,name=to_account,json=toAccount,proto3" json:"to_account,omitempty"` +} + +func (x *Transaction) Reset() { + *x = Transaction{} + if protoimpl.UnsafeEnabled { + mi := &file_banktransfer_banktransfer_proto_msgTypes[1] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *Transaction) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*Transaction) ProtoMessage() {} + +func (x *Transaction) ProtoReflect() protoreflect.Message { + mi := &file_banktransfer_banktransfer_proto_msgTypes[1] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use Transaction.ProtoReflect.Descriptor instead. +func (*Transaction) Descriptor() ([]byte, []int) { + return file_banktransfer_banktransfer_proto_rawDescGZIP(), []int{1} +} + +func (x *Transaction) GetId() int32 { + if x != nil { + return x.Id + } + return 0 +} + +func (x *Transaction) GetDonationId() int32 { + if x != nil { + return x.DonationId + } + return 0 +} + +func (x *Transaction) GetAmount() float32 { + if x != nil { + return x.Amount + } + return 0 +} + +func (x *Transaction) GetReference() string { + if x != nil { + return x.Reference + } + return "" +} + +func (x *Transaction) GetFromAccount() *Account { + if x != nil { + return x.FromAccount + } + return nil +} + +func (x *Transaction) GetToAccount() *Account { + if x != nil { + return x.ToAccount + } + return nil +} + +type ProcessingResponse struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Id int32 `protobuf:"varint,1,opt,name=id,proto3" json:"id,omitempty"` +} + +func (x *ProcessingResponse) Reset() { + *x = ProcessingResponse{} + if protoimpl.UnsafeEnabled { + mi := &file_banktransfer_banktransfer_proto_msgTypes[2] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *ProcessingResponse) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*ProcessingResponse) ProtoMessage() {} + +func (x *ProcessingResponse) ProtoReflect() protoreflect.Message { + mi := &file_banktransfer_banktransfer_proto_msgTypes[2] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use ProcessingResponse.ProtoReflect.Descriptor instead. +func (*ProcessingResponse) Descriptor() ([]byte, []int) { + return file_banktransfer_banktransfer_proto_rawDescGZIP(), []int{2} +} + +func (x *ProcessingResponse) GetId() int32 { + if x != nil { + return x.Id + } + return 0 +} + +var File_banktransfer_banktransfer_proto protoreflect.FileDescriptor + +var file_banktransfer_banktransfer_proto_rawDesc = []byte{ + 0x0a, 0x1f, 0x62, 0x61, 0x6e, 0x6b, 0x74, 0x72, 0x61, 0x6e, 0x73, 0x66, 0x65, 0x72, 0x2f, 0x62, + 0x61, 0x6e, 0x6b, 0x74, 0x72, 0x61, 0x6e, 0x73, 0x66, 0x65, 0x72, 0x2e, 0x70, 0x72, 0x6f, 0x74, + 0x6f, 0x12, 0x0c, 0x62, 0x61, 0x6e, 0x6b, 0x74, 0x72, 0x61, 0x6e, 0x73, 0x66, 0x65, 0x72, 0x1a, + 0x1b, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, + 0x2f, 0x65, 0x6d, 0x70, 0x74, 0x79, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x22, 0x52, 0x0a, 0x07, + 0x41, 0x63, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x12, 0x12, 0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18, + 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x1b, 0x0a, 0x09, 0x62, + 0x61, 0x6e, 0x6b, 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, + 0x62, 0x61, 0x6e, 0x6b, 0x4e, 0x61, 0x6d, 0x65, 0x12, 0x16, 0x0a, 0x06, 0x6e, 0x75, 0x6d, 0x62, + 0x65, 0x72, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x6e, 0x75, 0x6d, 0x62, 0x65, 0x72, + 0x22, 0xe4, 0x01, 0x0a, 0x0b, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, + 0x12, 0x0e, 0x0a, 0x02, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x05, 0x52, 0x02, 0x69, 0x64, + 0x12, 0x1f, 0x0a, 0x0b, 0x64, 0x6f, 0x6e, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x69, 0x64, 0x18, + 0x02, 0x20, 0x01, 0x28, 0x05, 0x52, 0x0a, 0x64, 0x6f, 0x6e, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x49, + 0x64, 0x12, 0x16, 0x0a, 0x06, 0x61, 0x6d, 0x6f, 0x75, 0x6e, 0x74, 0x18, 0x03, 0x20, 0x01, 0x28, + 0x02, 0x52, 0x06, 0x61, 0x6d, 0x6f, 0x75, 0x6e, 0x74, 0x12, 0x1c, 0x0a, 0x09, 0x72, 0x65, 0x66, + 0x65, 0x72, 0x65, 0x6e, 0x63, 0x65, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x72, 0x65, + 0x66, 0x65, 0x72, 0x65, 0x6e, 0x63, 0x65, 0x12, 0x38, 0x0a, 0x0c, 0x66, 0x72, 0x6f, 0x6d, 0x5f, + 0x61, 0x63, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x18, 0x05, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x15, 0x2e, + 0x62, 0x61, 0x6e, 0x6b, 0x74, 0x72, 0x61, 0x6e, 0x73, 0x66, 0x65, 0x72, 0x2e, 0x41, 0x63, 0x63, + 0x6f, 0x75, 0x6e, 0x74, 0x52, 0x0b, 0x66, 0x72, 0x6f, 0x6d, 0x41, 0x63, 0x63, 0x6f, 0x75, 0x6e, + 0x74, 0x12, 0x34, 0x0a, 0x0a, 0x74, 0x6f, 0x5f, 0x61, 0x63, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x18, + 0x06, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x15, 0x2e, 0x62, 0x61, 0x6e, 0x6b, 0x74, 0x72, 0x61, 0x6e, + 0x73, 0x66, 0x65, 0x72, 0x2e, 0x41, 0x63, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x52, 0x09, 0x74, 0x6f, + 0x41, 0x63, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x22, 0x24, 0x0a, 0x12, 0x50, 0x72, 0x6f, 0x63, 0x65, + 0x73, 0x73, 0x69, 0x6e, 0x67, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x0e, 0x0a, + 0x02, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x05, 0x52, 0x02, 0x69, 0x64, 0x32, 0xae, 0x01, + 0x0a, 0x0c, 0x42, 0x61, 0x6e, 0x6b, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x66, 0x65, 0x72, 0x12, 0x44, + 0x0a, 0x0d, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x66, 0x65, 0x72, 0x4d, 0x6f, 0x6e, 0x65, 0x79, 0x12, + 0x19, 0x2e, 0x62, 0x61, 0x6e, 0x6b, 0x74, 0x72, 0x61, 0x6e, 0x73, 0x66, 0x65, 0x72, 0x2e, 0x54, + 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x1a, 0x16, 0x2e, 0x67, 0x6f, 0x6f, + 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x45, 0x6d, 0x70, + 0x74, 0x79, 0x22, 0x00, 0x12, 0x58, 0x0a, 0x13, 0x50, 0x72, 0x6f, 0x63, 0x65, 0x73, 0x73, 0x54, + 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x12, 0x20, 0x2e, 0x62, 0x61, + 0x6e, 0x6b, 0x74, 0x72, 0x61, 0x6e, 0x73, 0x66, 0x65, 0x72, 0x2e, 0x50, 0x72, 0x6f, 0x63, 0x65, + 0x73, 0x73, 0x69, 0x6e, 0x67, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x1a, 0x19, 0x2e, + 0x62, 0x61, 0x6e, 0x6b, 0x74, 0x72, 0x61, 0x6e, 0x73, 0x66, 0x65, 0x72, 0x2e, 0x54, 0x72, 0x61, + 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x22, 0x00, 0x28, 0x01, 0x30, 0x01, 0x42, 0x59, + 0x5a, 0x57, 0x67, 0x69, 0x74, 0x6c, 0x61, 0x62, 0x2e, 0x72, 0x65, 0x75, 0x74, 0x6c, 0x69, 0x6e, + 0x67, 0x65, 0x6e, 0x2d, 0x75, 0x6e, 0x69, 0x76, 0x65, 0x72, 0x73, 0x69, 0x74, 0x79, 0x2e, 0x64, + 0x65, 0x2f, 0x61, 0x6c, 0x62, 0x72, 0x65, 0x63, 0x68, 0x74, 0x2f, 0x6d, 0x79, 0x61, 0x6b, 0x74, + 0x69, 0x6f, 0x6e, 0x2d, 0x67, 0x6f, 0x2f, 0x73, 0x72, 0x63, 0x2f, 0x62, 0x61, 0x6e, 0x6b, 0x74, + 0x72, 0x61, 0x6e, 0x73, 0x66, 0x65, 0x72, 0x2f, 0x67, 0x72, 0x70, 0x63, 0x2f, 0x62, 0x61, 0x6e, + 0x6b, 0x74, 0x72, 0x61, 0x6e, 0x73, 0x66, 0x65, 0x72, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, + 0x33, +} + +var ( + file_banktransfer_banktransfer_proto_rawDescOnce sync.Once + file_banktransfer_banktransfer_proto_rawDescData = file_banktransfer_banktransfer_proto_rawDesc +) + +func file_banktransfer_banktransfer_proto_rawDescGZIP() []byte { + file_banktransfer_banktransfer_proto_rawDescOnce.Do(func() { + file_banktransfer_banktransfer_proto_rawDescData = protoimpl.X.CompressGZIP(file_banktransfer_banktransfer_proto_rawDescData) + }) + return file_banktransfer_banktransfer_proto_rawDescData +} + +var file_banktransfer_banktransfer_proto_msgTypes = make([]protoimpl.MessageInfo, 3) +var file_banktransfer_banktransfer_proto_goTypes = []interface{}{ + (*Account)(nil), // 0: banktransfer.Account + (*Transaction)(nil), // 1: banktransfer.Transaction + (*ProcessingResponse)(nil), // 2: banktransfer.ProcessingResponse + (*empty.Empty)(nil), // 3: google.protobuf.Empty +} +var file_banktransfer_banktransfer_proto_depIdxs = []int32{ + 0, // 0: banktransfer.Transaction.from_account:type_name -> banktransfer.Account + 0, // 1: banktransfer.Transaction.to_account:type_name -> banktransfer.Account + 1, // 2: banktransfer.BankTransfer.TransferMoney:input_type -> banktransfer.Transaction + 2, // 3: banktransfer.BankTransfer.ProcessTransactions:input_type -> banktransfer.ProcessingResponse + 3, // 4: banktransfer.BankTransfer.TransferMoney:output_type -> google.protobuf.Empty + 1, // 5: banktransfer.BankTransfer.ProcessTransactions:output_type -> banktransfer.Transaction + 4, // [4:6] is the sub-list for method output_type + 2, // [2:4] is the sub-list for method input_type + 2, // [2:2] is the sub-list for extension type_name + 2, // [2:2] is the sub-list for extension extendee + 0, // [0:2] is the sub-list for field type_name +} + +func init() { file_banktransfer_banktransfer_proto_init() } +func file_banktransfer_banktransfer_proto_init() { + if File_banktransfer_banktransfer_proto != nil { + return + } + if !protoimpl.UnsafeEnabled { + file_banktransfer_banktransfer_proto_msgTypes[0].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*Account); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_banktransfer_banktransfer_proto_msgTypes[1].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*Transaction); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_banktransfer_banktransfer_proto_msgTypes[2].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*ProcessingResponse); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + } + type x struct{} + out := protoimpl.TypeBuilder{ + File: protoimpl.DescBuilder{ + GoPackagePath: reflect.TypeOf(x{}).PkgPath(), + RawDescriptor: file_banktransfer_banktransfer_proto_rawDesc, + NumEnums: 0, + NumMessages: 3, + NumExtensions: 0, + NumServices: 1, + }, + GoTypes: file_banktransfer_banktransfer_proto_goTypes, + DependencyIndexes: file_banktransfer_banktransfer_proto_depIdxs, + MessageInfos: file_banktransfer_banktransfer_proto_msgTypes, + }.Build() + File_banktransfer_banktransfer_proto = out.File + file_banktransfer_banktransfer_proto_rawDesc = nil + file_banktransfer_banktransfer_proto_goTypes = nil + file_banktransfer_banktransfer_proto_depIdxs = nil +} diff --git a/src/myaktion/client/banktransfer/banktransfer.proto b/src/myaktion/client/banktransfer/banktransfer.proto new file mode 100644 index 0000000000000000000000000000000000000000..a6ea937d1fde43ef2cfc5babc3dfc9a1a26bbf77 --- /dev/null +++ b/src/myaktion/client/banktransfer/banktransfer.proto @@ -0,0 +1,29 @@ +syntax = "proto3"; + +package banktransfer; + +import "google/protobuf/empty.proto"; + +option go_package = "gitlab.reutlingen-university.de/albrecht/myaktion-go/src/banktransfer/grpc/banktransfer"; + +service BankTransfer { + rpc TransferMoney (Transaction) returns (google.protobuf.Empty) {} + rpc ProcessTransactions (stream ProcessingResponse) returns (stream Transaction) {} +} + +message Account { + string name = 1; + string bank_name =2; + string number = 3; + } + message Transaction { + int32 id = 1; + int32 donation_id = 2; + float amount = 3; + string reference = 4; + Account from_account = 5; + Account to_account = 6; + } + message ProcessingResponse { + int32 id = 1; +} \ No newline at end of file diff --git a/src/myaktion/client/banktransfer/banktransfer_grpc.pb.go b/src/myaktion/client/banktransfer/banktransfer_grpc.pb.go new file mode 100644 index 0000000000000000000000000000000000000000..edc2f69bb4c4cb43109851e8c35fe280e995c79a --- /dev/null +++ b/src/myaktion/client/banktransfer/banktransfer_grpc.pb.go @@ -0,0 +1,180 @@ +// Code generated by protoc-gen-go-grpc. DO NOT EDIT. +// versions: +// - protoc-gen-go-grpc v1.3.0 +// - protoc v3.12.4 +// source: banktransfer/banktransfer.proto + +package banktransfer + +import ( + context "context" + empty "github.com/golang/protobuf/ptypes/empty" + grpc "google.golang.org/grpc" + codes "google.golang.org/grpc/codes" + status "google.golang.org/grpc/status" +) + +// This is a compile-time assertion to ensure that this generated file +// is compatible with the grpc package it is being compiled against. +// Requires gRPC-Go v1.32.0 or later. +const _ = grpc.SupportPackageIsVersion7 + +const ( + BankTransfer_TransferMoney_FullMethodName = "/banktransfer.BankTransfer/TransferMoney" + BankTransfer_ProcessTransactions_FullMethodName = "/banktransfer.BankTransfer/ProcessTransactions" +) + +// BankTransferClient is the client API for BankTransfer service. +// +// For semantics around ctx use and closing/ending streaming RPCs, please refer to https://pkg.go.dev/google.golang.org/grpc/?tab=doc#ClientConn.NewStream. +type BankTransferClient interface { + TransferMoney(ctx context.Context, in *Transaction, opts ...grpc.CallOption) (*empty.Empty, error) + ProcessTransactions(ctx context.Context, opts ...grpc.CallOption) (BankTransfer_ProcessTransactionsClient, error) +} + +type bankTransferClient struct { + cc grpc.ClientConnInterface +} + +func NewBankTransferClient(cc grpc.ClientConnInterface) BankTransferClient { + return &bankTransferClient{cc} +} + +func (c *bankTransferClient) TransferMoney(ctx context.Context, in *Transaction, opts ...grpc.CallOption) (*empty.Empty, error) { + out := new(empty.Empty) + err := c.cc.Invoke(ctx, BankTransfer_TransferMoney_FullMethodName, in, out, opts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *bankTransferClient) ProcessTransactions(ctx context.Context, opts ...grpc.CallOption) (BankTransfer_ProcessTransactionsClient, error) { + stream, err := c.cc.NewStream(ctx, &BankTransfer_ServiceDesc.Streams[0], BankTransfer_ProcessTransactions_FullMethodName, opts...) + if err != nil { + return nil, err + } + x := &bankTransferProcessTransactionsClient{stream} + return x, nil +} + +type BankTransfer_ProcessTransactionsClient interface { + Send(*ProcessingResponse) error + Recv() (*Transaction, error) + grpc.ClientStream +} + +type bankTransferProcessTransactionsClient struct { + grpc.ClientStream +} + +func (x *bankTransferProcessTransactionsClient) Send(m *ProcessingResponse) error { + return x.ClientStream.SendMsg(m) +} + +func (x *bankTransferProcessTransactionsClient) Recv() (*Transaction, error) { + m := new(Transaction) + if err := x.ClientStream.RecvMsg(m); err != nil { + return nil, err + } + return m, nil +} + +// BankTransferServer is the server API for BankTransfer service. +// All implementations must embed UnimplementedBankTransferServer +// for forward compatibility +type BankTransferServer interface { + TransferMoney(context.Context, *Transaction) (*empty.Empty, error) + ProcessTransactions(BankTransfer_ProcessTransactionsServer) error + mustEmbedUnimplementedBankTransferServer() +} + +// UnimplementedBankTransferServer must be embedded to have forward compatible implementations. +type UnimplementedBankTransferServer struct { +} + +func (UnimplementedBankTransferServer) TransferMoney(context.Context, *Transaction) (*empty.Empty, error) { + return nil, status.Errorf(codes.Unimplemented, "method TransferMoney not implemented") +} +func (UnimplementedBankTransferServer) ProcessTransactions(BankTransfer_ProcessTransactionsServer) error { + return status.Errorf(codes.Unimplemented, "method ProcessTransactions not implemented") +} +func (UnimplementedBankTransferServer) mustEmbedUnimplementedBankTransferServer() {} + +// UnsafeBankTransferServer may be embedded to opt out of forward compatibility for this service. +// Use of this interface is not recommended, as added methods to BankTransferServer will +// result in compilation errors. +type UnsafeBankTransferServer interface { + mustEmbedUnimplementedBankTransferServer() +} + +func RegisterBankTransferServer(s grpc.ServiceRegistrar, srv BankTransferServer) { + s.RegisterService(&BankTransfer_ServiceDesc, srv) +} + +func _BankTransfer_TransferMoney_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(Transaction) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(BankTransferServer).TransferMoney(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: BankTransfer_TransferMoney_FullMethodName, + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(BankTransferServer).TransferMoney(ctx, req.(*Transaction)) + } + return interceptor(ctx, in, info, handler) +} + +func _BankTransfer_ProcessTransactions_Handler(srv interface{}, stream grpc.ServerStream) error { + return srv.(BankTransferServer).ProcessTransactions(&bankTransferProcessTransactionsServer{stream}) +} + +type BankTransfer_ProcessTransactionsServer interface { + Send(*Transaction) error + Recv() (*ProcessingResponse, error) + grpc.ServerStream +} + +type bankTransferProcessTransactionsServer struct { + grpc.ServerStream +} + +func (x *bankTransferProcessTransactionsServer) Send(m *Transaction) error { + return x.ServerStream.SendMsg(m) +} + +func (x *bankTransferProcessTransactionsServer) Recv() (*ProcessingResponse, error) { + m := new(ProcessingResponse) + if err := x.ServerStream.RecvMsg(m); err != nil { + return nil, err + } + return m, nil +} + +// BankTransfer_ServiceDesc is the grpc.ServiceDesc for BankTransfer service. +// It's only intended for direct use with grpc.RegisterService, +// and not to be introspected or modified (even as a copy) +var BankTransfer_ServiceDesc = grpc.ServiceDesc{ + ServiceName: "banktransfer.BankTransfer", + HandlerType: (*BankTransferServer)(nil), + Methods: []grpc.MethodDesc{ + { + MethodName: "TransferMoney", + Handler: _BankTransfer_TransferMoney_Handler, + }, + }, + Streams: []grpc.StreamDesc{ + { + StreamName: "ProcessTransactions", + Handler: _BankTransfer_ProcessTransactions_Handler, + ServerStreams: true, + ClientStreams: true, + }, + }, + Metadata: "banktransfer/banktransfer.proto", +} diff --git a/src/myaktion/client/gen.go b/src/myaktion/client/gen.go new file mode 100644 index 0000000000000000000000000000000000000000..b45f11ff5ebca441fe314bbdb36dcdb1c602bc15 --- /dev/null +++ b/src/myaktion/client/gen.go @@ -0,0 +1,3 @@ +package client + +//go:generate protoc --go_out=. --go_opt=paths=source_relative --go-grpc_out=. --go-grpc_opt=paths=source_relative banktransfer/banktransfer.proto diff --git a/src/myaktion/docker-entrypoint.sh b/src/myaktion/docker-entrypoint.sh index 4fcb749ffa0bddfcb9c1ef607320164660dc1f26..928de3806ae06c5ebee1d6be24726a4ed45ef18d 100644 --- a/src/myaktion/docker-entrypoint.sh +++ b/src/myaktion/docker-entrypoint.sh @@ -8,5 +8,10 @@ if [ -n "$DB_CONNECT" ]; then /go/src/app/wait-for-it.sh "$DB_CONNECT" -t 40 fi +# Wait for banktransfer +if [ -n "$BANKTRANSFER_CONNECT" ]; then + /go/src/app/wait-for-it.sh "$BANKTRANSFER_CONNECT" -t 20 +fi + # Run the main container command. exec "$@" \ No newline at end of file diff --git a/src/myaktion/main.go b/src/myaktion/main.go index 04282aa5fe627420eca0b5a91507401b6ce69ae8..a434fc55c8f956bf08f472e45588caa98fd7c1a7 100644 --- a/src/myaktion/main.go +++ b/src/myaktion/main.go @@ -35,6 +35,7 @@ func main() { router.HandleFunc("/campaigns/{id}", handler.DeleteCampaign).Methods("DELETE") router.HandleFunc("/campaigns/{id}/donation", handler.AddDonation).Methods("POST") + go monitortransactions() if err := http.ListenAndServe(":8000", router); err != nil { log.Fatal(err) } diff --git a/src/myaktion/monitor.go b/src/myaktion/monitor.go new file mode 100644 index 0000000000000000000000000000000000000000..ad81999e7e0c08b69d961a64096ae2f6188a9fb8 --- /dev/null +++ b/src/myaktion/monitor.go @@ -0,0 +1,52 @@ +package main + +import ( + "context" + "time" + + log "github.com/sirupsen/logrus" + "gitlab.reutlingen-university.de/albrecht/myaktion-go/src/myaktion/client" + "gitlab.reutlingen-university.de/albrecht/myaktion-go/src/myaktion/client/banktransfer" +) + +func monitortransactions() { + for { + connectandmonitor() + time.Sleep(time.Second) + } +} + +func connectandmonitor() { + ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second) + defer cancel() + conn, err := client.GetBankTransferConnection(ctx) + if err != nil { + log.WithError(err).Fatal("error connecting to the banktransfer service") + } + defer conn.Close() + banktransferClient := banktransfer.NewBankTransferClient(conn) + watcher, err := banktransferClient.ProcessTransactions(ctx) + if err != nil { + log.WithError(err).Fatal("error watching transactions") + } + log.Info("Successfully connected to banktransfer service for processing transactions") + for { + transaction, err := watcher.Recv() + if err != nil { + if _, deadline := ctx.Deadline(); deadline { + log.Info("deadline reached. reconnect client") + break + } + log.WithError(err).Error("error receiving transaction") + continue + } + entry := log.WithField("transaction", transaction) + entry.Info("Received transaction. Sending processing response") + err = watcher.Send(&banktransfer.ProcessingResponse{Id: transaction.Id}) + if err != nil { + entry.WithError(err).Error("error sending processing response") + continue + } + entry.Info("Processing response sent") + } +} diff --git a/src/myaktion/service/donation.go b/src/myaktion/service/donation.go index 59786eb009e06745ec7a64898b40da2a88f9d090..d0104f4cda8909e1dd5ae743429da72ce0dc77d6 100644 --- a/src/myaktion/service/donation.go +++ b/src/myaktion/service/donation.go @@ -1,20 +1,73 @@ package service import ( + "context" + "time" + log "github.com/sirupsen/logrus" + "gitlab.reutlingen-university.de/albrecht/myaktion-go/src/myaktion/client" + "gitlab.reutlingen-university.de/albrecht/myaktion-go/src/myaktion/client/banktransfer" "gitlab.reutlingen-university.de/albrecht/myaktion-go/src/myaktion/db" "gitlab.reutlingen-university.de/albrecht/myaktion-go/src/myaktion/model" ) func AddDonation(campaignId uint, donation *model.Donation) error { + campaign, err := GetCampaign(campaignId) + if err != nil { + return err + } donation.CampaignID = campaignId result := db.DB.Create(donation) if result.Error != nil { return result.Error } + ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second) + defer cancel() + conn, err := client.GetBankTransferConnection(ctx) + if err != nil { + log.Errorf("error connecting to the banktransfer service: %v", err) + deleteDonation(donation) + return err + } + defer conn.Close() + banktransferClient := banktransfer.NewBankTransferClient(conn) + _, err = banktransferClient.TransferMoney(ctx, &banktransfer.Transaction{ + DonationId: int32(donation.ID), + Amount: float32(donation.Amount), + Reference: "Donation", + FromAccount: convertAccount(&donation.Account), + ToAccount: convertAccount(&campaign.Account), + }) + if err != nil { + log.Errorf("error calling the banktransfer service: %v", err) + deleteDonation(donation) + return err + } entry := log.WithField("ID", campaignId) entry.Info("Successfully added new donation to campaign in database.") entry.Tracef("Stored: %v", donation) return nil } + +// Helper-Funktionen +func convertAccount(account *model.Account) *banktransfer.Account { + return &banktransfer.Account{ + Name: account.Name, + BankName: account.BankName, + Number: account.Number, + } +} + +func deleteDonation(donation *model.Donation) error { + entry := log.WithField("donationID", donation.ID) + entry.Info("Trying to delete donation to make state consistent.") + result := db.DB.Delete(donation) + if result.Error != nil { + // Note: configure logger to raise an alarm to compensate inconsistent state + entry.WithField("alarm", true).Error("") + return result.Error + } + entry.Info("Successfully deleted campaign.") + return nil +}