blob: ae17dbb64a8502de4e0a6699cd149d809f2e9bd7 [file] [log] [blame]
Sergiusz Bazanskifb18c992019-05-01 12:27:03 +02001package main
2
3import (
4 "context"
5 "flag"
6
7 "github.com/golang/glog"
8 "google.golang.org/grpc/codes"
9 "google.golang.org/grpc/status"
10
Sergiusz Bazanski1446e982019-07-21 16:04:23 +020011 pb "code.hackerspace.pl/hscloud/bgpwtf/invoice/proto"
Sergiusz Bazanskifb18c992019-05-01 12:27:03 +020012 "code.hackerspace.pl/hscloud/go/mirko"
Sergiusz Bazanskifb18c992019-05-01 12:27:03 +020013)
14
15var (
16 flagDatabasePath string
17 flagInit bool
18 flagDisablePKI bool
19)
20
21type service struct {
22 m *model
23}
24
25func (s *service) CreateInvoice(ctx context.Context, req *pb.CreateInvoiceRequest) (*pb.CreateInvoiceResponse, error) {
Serge Bazanski220c5d22020-11-16 22:04:23 +010026 if err := validateInvoiceData(req.InvoiceData); err != nil {
27 return nil, status.Errorf(codes.InvalidArgument, "invoice data: %v", err)
Sergiusz Bazanskifb18c992019-05-01 12:27:03 +020028 }
29
Sergiusz Bazanski3976e3c2019-05-01 15:27:49 +020030 uid, err := s.m.createInvoice(ctx, req.InvoiceData)
Sergiusz Bazanskifb18c992019-05-01 12:27:03 +020031 if err != nil {
32 if _, ok := status.FromError(err); ok {
33 return nil, err
34 }
35 glog.Errorf("createInvoice(_, _): %v", err)
36 return nil, status.Error(codes.Unavailable, "could not create invoice")
37 }
38 return &pb.CreateInvoiceResponse{
39 Uid: uid,
40 }, nil
41}
42
43func (s *service) GetInvoice(ctx context.Context, req *pb.GetInvoiceRequest) (*pb.GetInvoiceResponse, error) {
44 invoice, err := s.m.getInvoice(ctx, req.Uid)
45 if err != nil {
46 if _, ok := status.FromError(err); ok {
47 return nil, err
48 }
49 glog.Errorf("getInvoice(_, %q): %v", req.Uid, err)
50 return nil, status.Error(codes.Unavailable, "internal server error")
51 }
Sergiusz Bazanskifb18c992019-05-01 12:27:03 +020052 res := &pb.GetInvoiceResponse{
53 Invoice: invoice,
54 }
Sergiusz Bazanskifb18c992019-05-01 12:27:03 +020055 return res, nil
56}
57
58func newService(m *model) *service {
59 return &service{
60 m: m,
61 }
62}
63
Sergiusz Bazanskia818ef22019-06-07 10:37:22 +020064func (s *service) invoicePDF(ctx context.Context, uid, language string) ([]byte, error) {
Sergiusz Bazanski57ef6b02019-05-01 14:08:29 +020065 sealed, err := s.m.getSealedUid(ctx, uid)
Sergiusz Bazanskifb18c992019-05-01 12:27:03 +020066 if err != nil {
Sergiusz Bazanski57ef6b02019-05-01 14:08:29 +020067 return nil, err
Sergiusz Bazanskifb18c992019-05-01 12:27:03 +020068 }
69
70 var rendered []byte
71 if sealed != "" {
72 // Invoice is sealed, return stored PDF.
Sergiusz Bazanski57ef6b02019-05-01 14:08:29 +020073 rendered, err = s.m.getRendered(ctx, uid)
Sergiusz Bazanskifb18c992019-05-01 12:27:03 +020074 if err != nil {
Sergiusz Bazanski57ef6b02019-05-01 14:08:29 +020075 return nil, err
Sergiusz Bazanskifb18c992019-05-01 12:27:03 +020076 }
77 } else {
78 // Invoice is proforma, render.
Sergiusz Bazanski57ef6b02019-05-01 14:08:29 +020079 invoice, err := s.m.getInvoice(ctx, uid)
Sergiusz Bazanskifb18c992019-05-01 12:27:03 +020080 if err != nil {
Sergiusz Bazanski57ef6b02019-05-01 14:08:29 +020081 return nil, err
Sergiusz Bazanskifb18c992019-05-01 12:27:03 +020082 }
83
Sergiusz Bazanskia818ef22019-06-07 10:37:22 +020084 rendered, err = renderInvoicePDF(invoice, language)
Sergiusz Bazanskifb18c992019-05-01 12:27:03 +020085 if err != nil {
Sergiusz Bazanski57ef6b02019-05-01 14:08:29 +020086 return nil, err
Sergiusz Bazanskifb18c992019-05-01 12:27:03 +020087 }
88 }
Sergiusz Bazanski57ef6b02019-05-01 14:08:29 +020089 return rendered, nil
90}
91
92func (s *service) RenderInvoice(req *pb.RenderInvoiceRequest, srv pb.Invoicer_RenderInvoiceServer) error {
Sergiusz Bazanskia818ef22019-06-07 10:37:22 +020093 rendered, err := s.invoicePDF(srv.Context(), req.Uid, req.Language)
Sergiusz Bazanski57ef6b02019-05-01 14:08:29 +020094 if err != nil {
95 if _, ok := status.FromError(err); ok {
96 return err
97 }
98 glog.Errorf("invoicePDF(_, %q): %v", req.Uid, err)
99 return status.Error(codes.Unavailable, "internal server error")
100 }
Sergiusz Bazanskifb18c992019-05-01 12:27:03 +0200101
102 chunkSize := 16 * 1024
103 chunk := &pb.RenderInvoiceResponse{}
104 for i := 0; i < len(rendered); i += chunkSize {
105 if i+chunkSize > len(rendered) {
106 chunk.Data = rendered[i:len(rendered)]
107 } else {
108 chunk.Data = rendered[i : i+chunkSize]
109 }
110 if err := srv.Send(chunk); err != nil {
111 glog.Errorf("srv.Send: %v", err)
112 return status.Error(codes.Unavailable, "stream broken")
113 }
114 }
115 return nil
116}
117
118func (s *service) SealInvoice(ctx context.Context, req *pb.SealInvoiceRequest) (*pb.SealInvoiceResponse, error) {
Sergiusz Bazanskia818ef22019-06-07 10:37:22 +0200119 useProformaTime := false
120 if req.DateSource == pb.SealInvoiceRequest_DATE_SOURCE_PROFORMA {
121 useProformaTime = true
122 }
123 if err := s.m.sealInvoice(ctx, req.Uid, req.Language, useProformaTime); err != nil {
Sergiusz Bazanskifb18c992019-05-01 12:27:03 +0200124 if _, ok := status.FromError(err); ok {
125 return nil, err
126 }
127 glog.Errorf("sealInvoice(_, %q): %v", req.Uid, err)
128 return nil, status.Error(codes.Unavailable, "internal server error")
129 }
130 return &pb.SealInvoiceResponse{}, nil
131}
132
Serge Bazanski1ecf22d2020-11-16 22:59:33 +0100133func (s *service) GetInvoices(req *pb.GetInvoicesRequest, srv pb.Invoicer_GetInvoicesServer) error {
134 return status.Error(codes.Unimplemented, "unimplemented")
135}
136
Sergiusz Bazanskifb18c992019-05-01 12:27:03 +0200137func init() {
138 flag.Set("logtostderr", "true")
139}
140
141func main() {
142 flag.StringVar(&flagDatabasePath, "db_path", "./foo.db", "path to sqlite database")
143 flag.BoolVar(&flagInit, "init_db", false, "init database and exit")
144 flag.Parse()
145
146 m, err := newModel(flagDatabasePath)
147 if err != nil {
148 glog.Exitf("newModel: %v", err)
149 }
150 if flagInit {
151 glog.Exit(m.init())
152 }
153
154 mi := mirko.New()
155 if err := mi.Listen(); err != nil {
156 glog.Exitf("Listen failed: %v", err)
157 }
158
159 s := newService(m)
Sergiusz Bazanski57ef6b02019-05-01 14:08:29 +0200160 s.setupStatusz(mi)
Sergiusz Bazanskifb18c992019-05-01 12:27:03 +0200161 pb.RegisterInvoicerServer(mi.GRPC(), s)
162
163 if err := mi.Serve(); err != nil {
164 glog.Exitf("Serve failed: %v", err)
165 }
166
167 <-mi.Done()
168}