@@ -5,88 +5,123 @@ import (
55 "encoding/base64"
66 "errors"
77 "fmt"
8+ "github.com/awakari/int-bluesky/model"
89 "github.com/bytedance/sonic"
910 ceProto "github.com/cloudevents/sdk-go/binding/format/protobuf/v2"
1011 "github.com/cloudevents/sdk-go/binding/format/protobuf/v2/pb"
1112 ce "github.com/cloudevents/sdk-go/v2/event"
1213 "io"
1314 "net/http"
15+ "net/url"
16+ "strings"
17+ "time"
1418)
1519
1620type Service interface {
17- CreateCallback (ctx context.Context , subId , url string ) (err error )
18- GetCallback (ctx context.Context , subId , url string ) (cb Callback , err error )
19- DeleteCallback (ctx context.Context , subId , url string ) (err error )
20- CountByInterest (ctx context.Context , interestId string ) (count int64 , err error )
21+ Subscribe (ctx context.Context , interestId , userId , groupId , url string , interval time. Duration ) (err error )
22+ Unsubscribe (ctx context.Context , interestId , userId , groupId , url string ) (err error )
23+ Subscription (ctx context.Context , interestId , userId , groupId , url string ) (sub Subscription , err error )
24+ CountByInterest (ctx context.Context , interestId , userId , groupId string ) (count int64 , err error )
2125 Read (ctx context.Context , interestId string , limit int ) (last []* pb.CloudEvent , err error )
2226}
2327
2428type service struct {
25- clientHttp * http.Client
26- uriBase string
29+ clientHttp * http.Client
30+ uriBase string
31+ tokenInternal string
2732}
2833
2934const keyHubCallback = "hub.callback"
3035const KeyHubMode = "hub.mode"
3136const KeyHubTopic = "hub.topic"
3237const modeSubscribe = "subscribe"
3338const modeUnsubscribe = "unsubscribe"
34- const fmtTopicUri = "%s/sub/%s/%s"
39+ const fmtTopicUri = "%s/v1/ sub/%s/%s"
3540const FmtJson = "json"
36- const fmtReadUri = "%s/sub/%s/%s?limit=%d"
41+ const fmtReadUri = "%s/v1/ sub/%s/%s?limit=%d"
3742
3843var ErrInternal = errors .New ("internal failure" )
3944var ErrConflict = errors .New ("conflict" )
4045var ErrNotFound = errors .New ("not found" )
4146
42- func NewService (clientHttp * http.Client , uriBase string ) Service {
47+ func NewService (clientHttp * http.Client , uriBase , tokenInternal string ) Service {
4348 return service {
44- clientHttp : clientHttp ,
45- uriBase : uriBase ,
49+ clientHttp : clientHttp ,
50+ uriBase : uriBase ,
51+ tokenInternal : tokenInternal ,
4652 }
4753}
4854
49- func (svc service ) CreateCallback (ctx context.Context , subId , callbackUrl string ) (err error ) {
50- err = svc .updateCallback (ctx , subId , callbackUrl , modeSubscribe )
55+ func (svc service ) Subscribe (ctx context.Context , interestId , userId , groupId , urlCallback string , interval time. Duration ) (err error ) {
56+ err = svc .updateCallback (ctx , interestId , userId , groupId , urlCallback , modeSubscribe , interval )
5157 return
5258}
5359
54- func (svc service ) CountByInterest (ctx context.Context , interestId string ) (count int64 , err error ) {
55- var req * http.Request
56- req , err = http .NewRequestWithContext (ctx , http .MethodGet , fmt .Sprintf ("%s/callbacks/list/%s" , svc .uriBase , interestId ), http .NoBody )
60+ func (svc service ) Unsubscribe (ctx context.Context , interestId , userId , groupId , urlCallback string ) (err error ) {
61+ err = svc .updateCallback (ctx , interestId , userId , groupId , urlCallback , modeUnsubscribe , 0 )
62+ return
63+ }
64+
65+ func (svc service ) updateCallback (ctx context.Context , interestId , userId , groupId , urlCallback , mode string , interval time.Duration ) (err error ) {
66+ topicUri := fmt .Sprintf (fmtTopicUri , svc .uriBase , FmtJson , interestId )
67+ data := url.Values {
68+ keyHubCallback : {
69+ urlCallback ,
70+ },
71+ KeyHubMode : {
72+ mode ,
73+ },
74+ KeyHubTopic : {
75+ topicUri ,
76+ },
77+ }
78+ reqUri := fmt .Sprintf ("%s/v2?format=%s&interestId=%s" , svc .uriBase , FmtJson , interestId )
79+ if interval > 0 && mode == modeSubscribe {
80+ reqUri += "&interval=" + interval .String ()
81+ }
82+
83+ req , err := http .NewRequestWithContext (ctx , http .MethodPost , reqUri , strings .NewReader (data .Encode ()))
5784 var resp * http.Response
5885 if err == nil {
86+ req .Header .Set ("Authorization" , "Bearer " + svc .tokenInternal )
87+ req .Header .Set (model .KeyGroupId , groupId )
88+ req .Header .Set (model .KeyUserId , userId )
89+ req .Header .Set ("Content-Type" , "application/x-www-form-urlencoded" )
5990 resp , err = svc .clientHttp .Do (req )
6091 }
92+
6193 switch err {
6294 case nil :
63- defer resp .Body .Close ()
6495 switch resp .StatusCode {
65- case http .StatusOK :
66- var cbl CallbackList
67- err = sonic .ConfigDefault .NewDecoder (resp .Body ).Decode (& cbl )
68- switch err {
69- case nil :
70- count = cbl .Count
71- default :
72- err = fmt .Errorf ("%w: %s" , ErrInternal , err )
73- }
96+ case http .StatusAccepted , http .StatusNoContent :
7497 case http .StatusNotFound :
75- err = ErrNotFound
98+ err = fmt .Errorf ("%w: callback not found for the subscription %s" , ErrConflict , interestId )
99+ case http .StatusConflict :
100+ err = fmt .Errorf ("%w: callback already registered for the subscription %s" , ErrConflict , interestId )
76101 default :
77- err = fmt .Errorf ("%w: response status %d" , ErrInternal , resp .StatusCode )
102+ defer resp .Body .Close ()
103+ respBody , _ := io .ReadAll (io .LimitReader (resp .Body , 0x1000 ))
104+ err = fmt .Errorf ("%w: unexpected create callback response %d, %s" , ErrInternal , resp .StatusCode , string (respBody ))
78105 }
79106 default :
80107 err = fmt .Errorf ("%w: %s" , ErrInternal , err )
81108 }
82109 return
83110}
84111
85- func (svc service ) GetCallback (ctx context.Context , subId , url string ) (cb Callback , err error ) {
112+ func (svc service ) Subscription (ctx context.Context , interestId , userId , groupId , url string ) (cb Subscription , err error ) {
86113 var req * http.Request
87- req , err = http .NewRequestWithContext (ctx , http .MethodGet , fmt .Sprintf ("%s/callbacks/%s/%s" , svc .uriBase , subId , base64 .URLEncoding .EncodeToString ([]byte (url ))), http .NoBody )
114+ req , err = http .NewRequestWithContext (
115+ ctx ,
116+ http .MethodGet ,
117+ fmt .Sprintf ("%s/v2?interestId=%s&url=%s" , svc .uriBase , interestId , base64 .URLEncoding .EncodeToString ([]byte (url ))),
118+ http .NoBody ,
119+ )
88120 var resp * http.Response
89121 if err == nil {
122+ req .Header .Set ("Authorization" , "Bearer " + svc .tokenInternal )
123+ req .Header .Set (model .KeyGroupId , groupId )
124+ req .Header .Set (model .KeyUserId , userId )
90125 resp , err = svc .clientHttp .Do (req )
91126 }
92127 switch err {
@@ -101,46 +136,38 @@ func (svc service) GetCallback(ctx context.Context, subId, url string) (cb Callb
101136 case http .StatusNotFound :
102137 err = ErrNotFound
103138 default :
104- err = fmt .Errorf ("%w: response status %d" , ErrInternal , resp .StatusCode )
139+ body , _ := io .ReadAll (io .LimitReader (resp .Body , 0x1000 ))
140+ err = fmt .Errorf ("%w: response %d, %s" , ErrInternal , resp .StatusCode , string (body ))
105141 }
106142 default :
107143 err = fmt .Errorf ("%w: %s" , ErrInternal , err )
108144 }
109145 return
110146}
111147
112- func (svc service ) DeleteCallback (ctx context.Context , subId , callbackUrl string ) (err error ) {
113- err = svc .updateCallback (ctx , subId , callbackUrl , modeUnsubscribe )
114- return
115- }
116-
117- func (svc service ) updateCallback (_ context.Context , subId , url , mode string ) (err error ) {
118- topicUri := fmt .Sprintf (fmtTopicUri , svc .uriBase , FmtJson , subId )
119- data := map [string ][]string {
120- keyHubCallback : {
121- url ,
122- },
123- KeyHubMode : {
124- mode ,
125- },
126- KeyHubTopic : {
127- topicUri ,
128- },
129- }
148+ func (svc service ) CountByInterest (ctx context.Context , interestId , userId , groupId string ) (count int64 , err error ) {
149+ var req * http.Request
150+ req , err = http .NewRequestWithContext (ctx , http .MethodGet , fmt .Sprintf ("%s/v2?interestId=%s" , svc .uriBase , interestId ), http .NoBody )
130151 var resp * http.Response
131- resp , err = svc .clientHttp .PostForm (topicUri , data )
152+ if err == nil {
153+ req .Header .Set ("Authorization" , "Bearer " + svc .tokenInternal )
154+ req .Header .Set (model .KeyGroupId , groupId )
155+ req .Header .Set (model .KeyUserId , userId )
156+ resp , err = svc .clientHttp .Do (req )
157+ }
132158 switch err {
133159 case nil :
160+ defer resp .Body .Close ()
134161 switch resp .StatusCode {
135- case http .StatusAccepted , http .StatusNoContent :
162+ case http .StatusOK :
163+ err = sonic .ConfigDefault .NewDecoder (resp .Body ).Decode (& count )
164+ if err != nil {
165+ err = fmt .Errorf ("%w: %s" , ErrInternal , err )
166+ }
136167 case http .StatusNotFound :
137- err = fmt .Errorf ("%w: callback not found for the subscription %s" , ErrConflict , subId )
138- case http .StatusConflict :
139- err = fmt .Errorf ("%w: callback already registered for the subscription %s" , ErrConflict , subId )
168+ err = ErrNotFound
140169 default :
141- defer resp .Body .Close ()
142- respBody , _ := io .ReadAll (resp .Body )
143- err = fmt .Errorf ("%w: unexpected create callback response %d, %s" , ErrInternal , resp .StatusCode , string (respBody ))
170+ err = fmt .Errorf ("%w: response status %d" , ErrInternal , resp .StatusCode )
144171 }
145172 default :
146173 err = fmt .Errorf ("%w: %s" , ErrInternal , err )
0 commit comments