@@ -24,6 +24,7 @@ import (
24
24
"net"
25
25
"net/http"
26
26
"net/url"
27
+ "strconv"
27
28
"strings"
28
29
"time"
29
30
@@ -34,6 +35,8 @@ import (
34
35
35
36
var _ runtime.Satori = & SatoriClient {}
36
37
38
+ type CtxTokenIDKey struct {}
39
+
37
40
type SatoriClient struct {
38
41
logger * zap.Logger
39
42
httpc * http.Client
@@ -117,10 +120,11 @@ func (stc *sessionTokenClaims) Valid() error {
117
120
return nil
118
121
}
119
122
120
- func (s * SatoriClient ) generateToken (id string ) (string , error ) {
123
+ func (s * SatoriClient ) generateToken (ctx context.Context , id string ) (string , error ) {
124
+ tid := ctx .Value (CtxTokenIDKey {}).(string )
121
125
timestamp := time .Now ().UTC ()
122
126
claims := sessionTokenClaims {
123
- SessionID : "" ,
127
+ SessionID : tid ,
124
128
IdentityId : id ,
125
129
ExpiresAt : timestamp .Add (time .Duration (s .tokenExpirySec ) * time .Second ).Unix (),
126
130
IssuedAt : timestamp .Unix (),
@@ -135,23 +139,27 @@ func (s *SatoriClient) generateToken(id string) (string, error) {
135
139
}
136
140
137
141
type authenticateBody struct {
138
- Id string `json:"id"`
142
+ Id string `json:"id"`
143
+ Default map [string ]string `json:"default,omitempty"`
144
+ Custom map [string ]string `json:"custom,omitempty"`
139
145
}
140
146
141
147
// @group satori
142
148
// @summary Create a new identity.
143
149
// @param ctx(type=context.Context) The context object represents information about the server and requester.
144
150
// @param id(type=string) The identifier of the identity.
145
- // @param ipAddress(type=string, optional=true) An optional client IP address to pass on to Satori for geo-IP lookup.
151
+ // @param default(type=map[string]string, optional=true, default=nil) Default properties to update with this call. Set to nil to leave them as they are on the server.
152
+ // @param custom(type=map[string]string, optional=true, default=nil) Custom properties to update with this call. Set to nil to leave them as they are on the server.
153
+ // @param ipAddress(type=string, optional=true, default="") An optional client IP address to pass on to Satori for geo-IP lookup.
146
154
// @return error(error) An optional error value if an error occurred.
147
- func (s * SatoriClient ) Authenticate (ctx context.Context , id string , ipAddress ... string ) error {
155
+ func (s * SatoriClient ) Authenticate (ctx context.Context , id string , defaultProperties , customProperties map [ string ] string , ipAddress ... string ) error {
148
156
if s .invalidConfig {
149
157
return runtime .ErrSatoriConfigurationInvalid
150
158
}
151
159
152
160
url := s .url .String () + "/v1/authenticate"
153
161
154
- body := & authenticateBody {Id : id }
162
+ body := & authenticateBody {Id : id , Default : defaultProperties , Custom : customProperties }
155
163
156
164
json , err := json .Marshal (body )
157
165
if err != nil {
@@ -200,7 +208,7 @@ func (s *SatoriClient) PropertiesGet(ctx context.Context, id string) (*runtime.P
200
208
201
209
url := s .url .String () + "/v1/properties"
202
210
203
- sessionToken , err := s .generateToken (id )
211
+ sessionToken , err := s .generateToken (ctx , id )
204
212
if err != nil {
205
213
return nil , err
206
214
}
@@ -249,7 +257,7 @@ func (s *SatoriClient) PropertiesUpdate(ctx context.Context, id string, properti
249
257
250
258
url := s .url .String () + "/v1/properties"
251
259
252
- sessionToken , err := s .generateToken (id )
260
+ sessionToken , err := s .generateToken (ctx , id )
253
261
if err != nil {
254
262
return err
255
263
}
@@ -315,7 +323,7 @@ func (s *SatoriClient) EventsPublish(ctx context.Context, id string, events []*r
315
323
evts [i ].setTimestamp ()
316
324
}
317
325
318
- sessionToken , err := s .generateToken (id )
326
+ sessionToken , err := s .generateToken (ctx , id )
319
327
if err != nil {
320
328
return err
321
329
}
@@ -361,7 +369,7 @@ func (s *SatoriClient) ExperimentsList(ctx context.Context, id string, names ...
361
369
362
370
url := s .url .String () + "/v1/experiment"
363
371
364
- sessionToken , err := s .generateToken (id )
372
+ sessionToken , err := s .generateToken (ctx , id )
365
373
if err != nil {
366
374
return nil , err
367
375
}
@@ -419,7 +427,7 @@ func (s *SatoriClient) FlagsList(ctx context.Context, id string, names ...string
419
427
420
428
url := s .url .String () + "/v1/flag"
421
429
422
- sessionToken , err := s .generateToken (id )
430
+ sessionToken , err := s .generateToken (ctx , id )
423
431
if err != nil {
424
432
return nil , err
425
433
}
@@ -477,7 +485,7 @@ func (s *SatoriClient) LiveEventsList(ctx context.Context, id string, names ...s
477
485
478
486
url := s .url .String () + "/v1/live-event"
479
487
480
- sessionToken , err := s .generateToken (id )
488
+ sessionToken , err := s .generateToken (ctx , id )
481
489
if err != nil {
482
490
return nil , err
483
491
}
@@ -519,3 +527,157 @@ func (s *SatoriClient) LiveEventsList(ctx context.Context, id string, names ...s
519
527
return nil , fmt .Errorf ("%d status code" , res .StatusCode )
520
528
}
521
529
}
530
+
531
+ // @group satori
532
+ // @summary List messages.
533
+ // @param ctx(type=context.Context) The context object represents information about the server and requester.
534
+ // @param id(type=string) The identifier of the identity.
535
+ // @param limit(type=int) The max number of messages to return.
536
+ // @param forward(type=bool) True if listing should be older messages to newer, false if reverse.
537
+ // @param cursor(type=string) A pagination cursor, if any.
538
+ // @return messages(*runtime.SatoriMessageList) The messages list.
539
+ // @return error(error) An optional error value if an error occurred.
540
+ func (s * SatoriClient ) MessagesList (ctx context.Context , id string , limit int , forward bool , cursor string ) (* runtime.SatoriMessageList , error ) {
541
+ if s .invalidConfig {
542
+ return nil , runtime .ErrSatoriConfigurationInvalid
543
+ }
544
+
545
+ if limit < 1 {
546
+ return nil , errors .New ("limit must be greater than zero" )
547
+ }
548
+
549
+ url := s .url .String () + "/v1/message"
550
+
551
+ sessionToken , err := s .generateToken (ctx , id )
552
+ if err != nil {
553
+ return nil , err
554
+ }
555
+
556
+ req , err := http .NewRequestWithContext (ctx , "GET" , url , nil )
557
+ if err != nil {
558
+ return nil , err
559
+ }
560
+ req .Header .Set ("Authorization" , fmt .Sprintf ("Bearer %s" , sessionToken ))
561
+ q := req .URL .Query ()
562
+ q .Set ("limit" , strconv .Itoa (limit ))
563
+ q .Set ("forward" , strconv .FormatBool (forward ))
564
+ if cursor != "" {
565
+ q .Set ("cursor" , cursor )
566
+ }
567
+ req .URL .RawQuery = q .Encode ()
568
+
569
+ res , err := s .httpc .Do (req )
570
+ if err != nil {
571
+ return nil , err
572
+ }
573
+
574
+ defer res .Body .Close ()
575
+
576
+ switch res .StatusCode {
577
+ case 200 :
578
+ resBody , err := io .ReadAll (res .Body )
579
+ if err != nil {
580
+ return nil , err
581
+ }
582
+ var messages runtime.SatoriMessageList
583
+ if err = json .Unmarshal (resBody , & messages ); err != nil {
584
+ return nil , err
585
+ }
586
+
587
+ return & messages , nil
588
+ default :
589
+ return nil , fmt .Errorf ("%d status code" , res .StatusCode )
590
+ }
591
+ }
592
+
593
+ // @group satori
594
+ // @summary Update message.
595
+ // @param ctx(type=context.Context) The context object represents information about the server and requester.
596
+ // @param id(type=string) The identifier of the identity.
597
+ // @param readTime(type=int64) The time the message was read at the client.
598
+ // @param consumeTime(type=int64) The time the message was consumed by the identity.
599
+ // @return error(error) An optional error value if an error occurred.
600
+ func (s * SatoriClient ) MessageUpdate (ctx context.Context , id , messageId string , readTime , consumeTime int64 ) error {
601
+ if s .invalidConfig {
602
+ return runtime .ErrSatoriConfigurationInvalid
603
+ }
604
+
605
+ url := s .url .String () + fmt .Sprintf ("/v1/message/%s" , messageId )
606
+
607
+ sessionToken , err := s .generateToken (ctx , id )
608
+ if err != nil {
609
+ return err
610
+ }
611
+
612
+ json , err := json .Marshal (& runtime.SatoriMessageUpdate {
613
+ ReadTime : readTime ,
614
+ ConsumeTime : consumeTime ,
615
+ })
616
+ if err != nil {
617
+ return err
618
+ }
619
+
620
+ req , err := http .NewRequestWithContext (ctx , "PUT" , url , bytes .NewReader (json ))
621
+ if err != nil {
622
+ return err
623
+ }
624
+ req .Header .Set ("Content-Type" , "application/json" )
625
+ req .Header .Set ("Authorization" , fmt .Sprintf ("Bearer %s" , sessionToken ))
626
+
627
+ res , err := s .httpc .Do (req )
628
+ if err != nil {
629
+ return err
630
+ }
631
+
632
+ defer res .Body .Close ()
633
+
634
+ switch res .StatusCode {
635
+ case 200 :
636
+ return nil
637
+ default :
638
+ return fmt .Errorf ("%d status code" , res .StatusCode )
639
+ }
640
+ }
641
+
642
+ // @group satori
643
+ // @summary Delete message.
644
+ // @param ctx(type=context.Context) The context object represents information about the server and requester.
645
+ // @param id(type=string) The identifier of the identity.
646
+ // @param messageId(type=string) The identifier of the message.
647
+ // @return error(error) An optional error value if an error occurred.
648
+ func (s * SatoriClient ) MessageDelete (ctx context.Context , id , messageId string ) error {
649
+ if s .invalidConfig {
650
+ return runtime .ErrSatoriConfigurationInvalid
651
+ }
652
+
653
+ if messageId == "" {
654
+ return errors .New ("message id cannot be an empty string" )
655
+ }
656
+
657
+ url := s .url .String () + fmt .Sprintf ("/v1/message/%s" , messageId )
658
+
659
+ sessionToken , err := s .generateToken (ctx , id )
660
+ if err != nil {
661
+ return err
662
+ }
663
+
664
+ req , err := http .NewRequestWithContext (ctx , "DELETE" , url , nil )
665
+ if err != nil {
666
+ return err
667
+ }
668
+ req .Header .Set ("Authorization" , fmt .Sprintf ("Bearer %s" , sessionToken ))
669
+
670
+ res , err := s .httpc .Do (req )
671
+ if err != nil {
672
+ return err
673
+ }
674
+
675
+ defer res .Body .Close ()
676
+
677
+ switch res .StatusCode {
678
+ case 200 :
679
+ return nil
680
+ default :
681
+ return fmt .Errorf ("%d status code" , res .StatusCode )
682
+ }
683
+ }
0 commit comments