-
Notifications
You must be signed in to change notification settings - Fork 1
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
27 changed files
with
622 additions
and
1,418 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,29 @@ | ||
package reader | ||
|
||
import ( | ||
"fmt" | ||
"strconv" | ||
"strings" | ||
) | ||
|
||
type Callback struct { | ||
Url string `json:"url"` | ||
Format string `json:"fmt"` | ||
} | ||
|
||
func MakeCallbackUrl(urlBase string, chatId int64) string { | ||
return urlBase + "/" + strconv.FormatInt(chatId, 10) | ||
} | ||
|
||
func GetCallbackUrlChatId(cbUrl string) (chatId int64, err error) { | ||
cbUrlParts := strings.Split(cbUrl, "/") | ||
cbUrlPartsLen := len(cbUrlParts) | ||
if cbUrlPartsLen < 1 { | ||
err = fmt.Errorf("invalid callback url") | ||
} | ||
if err == nil { | ||
chatIdStr := cbUrlParts[cbUrlPartsLen-1] | ||
chatId, err = strconv.ParseInt(chatIdStr, 10, 64) | ||
} | ||
return | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,50 @@ | ||
package reader | ||
|
||
import ( | ||
"context" | ||
"fmt" | ||
"log/slog" | ||
) | ||
|
||
type serviceLogging struct { | ||
svc Service | ||
log *slog.Logger | ||
} | ||
|
||
func NewServiceLogging(svc Service, log *slog.Logger) Service { | ||
return serviceLogging{ | ||
svc: svc, | ||
log: log, | ||
} | ||
} | ||
|
||
func (sl serviceLogging) CreateCallback(ctx context.Context, subId, url string) (err error) { | ||
err = sl.svc.CreateCallback(ctx, subId, url) | ||
ll := sl.logLevel(err) | ||
sl.log.Log(ctx, ll, fmt.Sprintf("reader.CreateCallback(%s, %s): err=%s", subId, url, err)) | ||
return | ||
} | ||
|
||
func (sl serviceLogging) GetCallback(ctx context.Context, subId string) (cb Callback, err error) { | ||
cb, err = sl.svc.GetCallback(ctx, subId) | ||
ll := sl.logLevel(err) | ||
sl.log.Log(ctx, ll, fmt.Sprintf("reader.GetCallback(%s): %+v, err=%s", subId, cb, err)) | ||
return | ||
} | ||
|
||
func (sl serviceLogging) DeleteCallback(ctx context.Context, subId, url string) (err error) { | ||
err = sl.svc.DeleteCallback(ctx, subId, url) | ||
ll := sl.logLevel(err) | ||
sl.log.Log(ctx, ll, fmt.Sprintf("reader.DeleteCallback(%s, %s): err=%s", subId, url, err)) | ||
return | ||
} | ||
|
||
func (sl serviceLogging) logLevel(err error) (lvl slog.Level) { | ||
switch err { | ||
case nil: | ||
lvl = slog.LevelInfo | ||
default: | ||
lvl = slog.LevelError | ||
} | ||
return | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,105 @@ | ||
package reader | ||
|
||
import ( | ||
"context" | ||
"encoding/json" | ||
"errors" | ||
"fmt" | ||
"net/http" | ||
) | ||
|
||
type Service interface { | ||
CreateCallback(ctx context.Context, subId, url string) (err error) | ||
GetCallback(ctx context.Context, subId string) (cb Callback, err error) | ||
DeleteCallback(ctx context.Context, subId, url string) (err error) | ||
} | ||
|
||
type service struct { | ||
clientHttp *http.Client | ||
uriBase string | ||
} | ||
|
||
const keyHubCallback = "hub.callback" | ||
const KeyHubMode = "hub.mode" | ||
const KeyHubTopic = "hub.topic" | ||
const modeSubscribe = "subscribe" | ||
const modeUnsubscribe = "unsubscribe" | ||
const fmtTopicUri = "%s/sub/%s/%s" | ||
const FmtJson = "json" | ||
|
||
var ErrInternal = errors.New("internal failure") | ||
var ErrConflict = errors.New("conflict") | ||
var ErrNotFound = errors.New("not found") | ||
|
||
func NewService(clientHttp *http.Client, uriBase string) Service { | ||
return service{ | ||
clientHttp: clientHttp, | ||
uriBase: uriBase, | ||
} | ||
} | ||
|
||
func (svc service) CreateCallback(ctx context.Context, subId, callbackUrl string) (err error) { | ||
err = svc.updateCallback(ctx, subId, callbackUrl, modeSubscribe) | ||
return | ||
} | ||
|
||
func (svc service) GetCallback(ctx context.Context, subId string) (cb Callback, err error) { | ||
var resp *http.Response | ||
resp, err = svc.clientHttp.Get(fmt.Sprintf("/callbacks/%s/%s", svc.uriBase, subId)) | ||
switch err { | ||
case nil: | ||
defer resp.Body.Close() | ||
switch resp.StatusCode { | ||
case http.StatusOK: | ||
err = json.NewDecoder(resp.Body).Decode(&cb) | ||
if err != nil { | ||
err = fmt.Errorf("%w: %s", ErrInternal, err) | ||
} | ||
case http.StatusNotFound: | ||
err = ErrNotFound | ||
default: | ||
err = fmt.Errorf("%w: response status %d", ErrInternal, resp.StatusCode) | ||
} | ||
err = json.NewDecoder(resp.Body).Decode(&cb) | ||
default: | ||
err = fmt.Errorf("%w: %s", ErrInternal, err) | ||
} | ||
return | ||
} | ||
|
||
func (svc service) DeleteCallback(ctx context.Context, subId, callbackUrl string) (err error) { | ||
err = svc.updateCallback(ctx, subId, callbackUrl, modeUnsubscribe) | ||
return | ||
} | ||
|
||
func (svc service) updateCallback(_ context.Context, subId, url, mode string) (err error) { | ||
topicUri := fmt.Sprintf(fmtTopicUri, svc.uriBase, FmtJson, subId) | ||
data := map[string][]string{ | ||
keyHubCallback: { | ||
url, | ||
}, | ||
KeyHubMode: { | ||
mode, | ||
}, | ||
KeyHubTopic: { | ||
topicUri, | ||
}, | ||
} | ||
var resp *http.Response | ||
resp, err = svc.clientHttp.PostForm(topicUri, data) | ||
switch err { | ||
case nil: | ||
switch resp.StatusCode { | ||
case http.StatusAccepted, http.StatusNoContent: | ||
case http.StatusNotFound: | ||
err = fmt.Errorf("%w: callback not found for the subscription %s", ErrConflict, subId) | ||
case http.StatusConflict: | ||
err = fmt.Errorf("%w: callback already registered for the subscription %s", ErrConflict, subId) | ||
default: | ||
err = fmt.Errorf("%w: unexpected create callback response %d", ErrInternal, resp.StatusCode) | ||
} | ||
default: | ||
err = fmt.Errorf("%w: %s", ErrInternal, err) | ||
} | ||
return | ||
} |
Oops, something went wrong.