11package rest
22
33import (
4+ "bytes"
5+ "errors"
6+ "fmt"
47 "io"
58 "log"
69 "net/http"
@@ -10,66 +13,94 @@ import (
1013 "github.com/pasarguard/node/common"
1114)
1215
13- func (s * Service ) SyncUser (w http.ResponseWriter , r * http.Request ) {
14- body , err := io .ReadAll (r .Body )
15- if err != nil {
16- http .Error (w , "Failed to read request body" , http .StatusBadRequest )
17- return
16+ const (
17+ requestChunkSize = 64 * 1024 // 64KB streaming chunks
18+ )
19+
20+ func readRequestBody (body io.ReadCloser ) ([]byte , error ) {
21+ defer body .Close ()
22+
23+ var buf bytes.Buffer
24+ tmp := make ([]byte , requestChunkSize )
25+ for {
26+ n , err := body .Read (tmp )
27+ if n > 0 {
28+ if _ , werr := buf .Write (tmp [:n ]); werr != nil {
29+ return nil , werr
30+ }
31+ }
32+ if errors .Is (err , io .EOF ) {
33+ break
34+ }
35+ if err != nil {
36+ return nil , err
37+ }
1838 }
19- defer r .Body .Close ()
2039
21- user := & common.User {}
22- if err = proto .Unmarshal (body , user ); err != nil {
23- http .Error (w , "Failed to decode user" , http .StatusBadRequest )
24- return
40+ if buf .Len () == 0 {
41+ return nil , io .ErrUnexpectedEOF
2542 }
2643
27- if user == nil {
28- http .Error (w , "no user received" , http .StatusBadRequest )
29- return
44+ return buf .Bytes (), nil
45+ }
46+
47+ func decodeUsersPayload (data []byte ) ([]* common.User , error ) {
48+ if len (data ) == 0 {
49+ return nil , io .ErrUnexpectedEOF
3050 }
3151
32- log .Printf ("Got user: %v" , user .GetEmail ())
52+ // First try a Users envelope for batch updates.
53+ users := & common.Users {}
54+ if err := proto .Unmarshal (data , users ); err == nil && len (users .GetUsers ()) > 0 {
55+ return users .GetUsers (), nil
56+ }
3357
34- if err = s . Backend (). SyncUser ( r . Context (), user ); err != nil {
35- log . Printf ( "Error syncing user: %v" , err )
36- http . Error ( w , err . Error (), http . StatusInternalServerError )
37- return
58+ // Fallback to single user payload.
59+ user := & common. User {}
60+ if err := proto . Unmarshal ( data , user ); err == nil && user . GetEmail () != "" {
61+ return [] * common. User { user }, nil
3862 }
3963
40- response , _ := proto .Marshal (& common.Empty {})
64+ return nil , fmt .Errorf ("failed to decode user payload" )
65+ }
4166
42- w .Header ().Set ("Content-Type" , "application/x-protobuf" )
43- if _ , err = w .Write (response ); err != nil {
44- http .Error (w , "Failed to write response" , http .StatusInternalServerError )
67+ func (s * Service ) SyncUser (w http.ResponseWriter , r * http.Request ) {
68+ body , err := readRequestBody (r .Body )
69+ if err != nil {
70+ http .Error (w , fmt .Sprintf ("Failed to read request body: %v" , err ), http .StatusBadRequest )
4571 return
4672 }
47- }
4873
49- func (s * Service ) SyncUsers (w http.ResponseWriter , r * http.Request ) {
50- body , err := io .ReadAll (r .Body )
74+ users , err := decodeUsersPayload (body )
5175 if err != nil {
52- http .Error (w , "Failed to read request body" , http .StatusBadRequest )
76+ http .Error (w , fmt . Sprintf ( "Failed to decode user payload: %v" , err ) , http .StatusBadRequest )
5377 return
5478 }
55- defer r .Body .Close ()
5679
80+ for _ , user := range users {
81+ log .Printf ("Got user: %v" , user .GetEmail ())
82+
83+ if err = s .Backend ().SyncUser (r .Context (), user ); err != nil {
84+ log .Printf ("Error syncing user: %v" , err )
85+ http .Error (w , err .Error (), http .StatusInternalServerError )
86+ return
87+ }
88+ }
89+
90+ common .SendProtoResponse (w , & common.Empty {})
91+ }
92+
93+ func (s * Service ) SyncUsers (w http.ResponseWriter , r * http.Request ) {
5794 users := & common.Users {}
58- if err = proto . Unmarshal ( body , users ); err != nil {
59- http .Error (w , "Failed to decode user" , http .StatusBadRequest )
95+ if err := common . ReadProtoBody ( r . Body , users ); err != nil {
96+ http .Error (w , fmt . Sprintf ( "Failed to decode user payload: %v" , err ) , http .StatusBadRequest )
6097 return
6198 }
6299
63- if err = s .Backend ().SyncUsers (r .Context (), users .GetUsers ()); err != nil {
100+ if err : = s .Backend ().SyncUsers (r .Context (), users .GetUsers ()); err != nil {
64101 http .Error (w , err .Error (), http .StatusInternalServerError )
65102 return
66103 }
67104
68- response , _ := proto .Marshal (& common.Empty {})
69-
70- w .Header ().Set ("Content-Type" , "application/x-protobuf" )
71- if _ , err = w .Write (response ); err != nil {
72- http .Error (w , "Failed to write response" , http .StatusInternalServerError )
73- return
74- }
105+ common .SendProtoResponse (w , & common.Empty {})
75106}
0 commit comments