Skip to content

Commit

Permalink
feat(api): add online badge
Browse files Browse the repository at this point in the history
  • Loading branch information
ernado committed Apr 18, 2024
1 parent c9c7bad commit 554d7a6
Show file tree
Hide file tree
Showing 11 changed files with 717 additions and 114 deletions.
52 changes: 35 additions & 17 deletions _oas/openapi.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,22 @@ paths:
$ref: "#/components/schemas/Status"
default:
$ref: "#/components/responses/Error"
/badge/telegram/online:
parameters:
- required: true
in: query
name: groups
schema:
type: array
items:
type: string
get:
operationId: "getTelegramOnlineBadge"
responses:
200:
$ref: "#/components/responses/SVG"
default:
$ref: "#/components/responses/Error"
/badge/telegram/{group_name}:
parameters:
- required: true
Expand All @@ -43,23 +59,7 @@ paths:
type: string
responses:
200:
description: Badge
headers:
Cache-Control:
description: "The Cache-Control header provides important info on how long a response may be considered fresh"
schema:
type: string
example: "max-age=3600, public, must-revalidate"
ETag:
description: "The ETag header provides a unique identifier for the response"
schema:
type: string
example: "W/\"123456789\""
content:
"image/svg+xml":
schema:
type: string
format: binary
$ref: "#/components/responses/SVG"
default:
$ref: "#/components/responses/Error"
components:
Expand All @@ -70,6 +70,24 @@ components:
"application/json":
schema:
$ref: "#/components/schemas/Error"
SVG:
description: Badge
headers:
Cache-Control:
description: "The Cache-Control header provides important info on how long a response may be considered fresh"
schema:
type: string
example: "max-age=3600, public, must-revalidate"
ETag:
description: "The ETag header provides a unique identifier for the response"
schema:
type: string
example: "W/\"123456789\""
content:
"image/svg+xml":
schema:
type: string
format: binary
schemas:
Error:
type: object
Expand Down
107 changes: 72 additions & 35 deletions internal/api/badge.go
Original file line number Diff line number Diff line change
Expand Up @@ -36,38 +36,7 @@ func etag(name string, data []byte) string {
return fmt.Sprintf(`W/"%s-%d-%08X"`, name, len(data), crc)
}

func (s Server) GetTelegramBadge(ctx context.Context, params oas.GetTelegramBadgeParams) (*oas.GetTelegramBadgeOKHeaders, error) {
var members int
{
peer, err := s.resolver.ResolveDomain(ctx, params.GroupName)
if err != nil {
return nil, errors.Wrap(err, "resolve domain")
}
var inputChannel tg.InputChannel
inputChannel.FillFrom(peer.(*tg.InputPeerChannel))
full, err := s.tg.API().ChannelsGetFullChannel(ctx, &inputChannel)
if err != nil {
return nil, errors.Wrap(err, "get chat")
}
members = full.FullChat.(*tg.ChannelFull).ParticipantsCount
s.lg.Info("Got chat",
zap.Int("participants", members),
)
}
var (
title = params.Title.Or(params.GroupName)
text = strconv.Itoa(members)
u = &url.URL{
Scheme: "https",
Host: "img.shields.io",
Path: generateBadgePath(title, text, "179cde"),
}
)
{
q := u.Query()
q.Set("logo", "telegram")
u.RawQuery = q.Encode()
}
func (s Server) download(ctx context.Context, u *url.URL) (*oas.SVGHeaders, error) {
req, err := http.NewRequestWithContext(ctx, http.MethodGet, u.String(), http.NoBody)
if err != nil {
return nil, errors.Wrap(err, "create request")
Expand All @@ -82,11 +51,79 @@ func (s Server) GetTelegramBadge(ctx context.Context, params oas.GetTelegramBadg
return nil, errors.Wrap(err, "read body")
}

return &oas.GetTelegramBadgeOKHeaders{
return &oas.SVGHeaders{
CacheControl: oas.NewOptString("no-cache"),
ETag: oas.NewOptString(etag(params.GroupName, data)),
Response: oas.GetTelegramBadgeOK{
ETag: oas.NewOptString(etag("svg", data)),
Response: oas.SVG{
Data: bytes.NewReader(data),
},
}, nil
}

func (s Server) fetchChannel(ctx context.Context, name string) (*tg.ChannelFull, error) {
peer, err := s.resolver.ResolveDomain(ctx, name)
if err != nil {
return nil, errors.Wrap(err, "resolve domain")
}
var inputChannel tg.InputChannel
inputChannel.FillFrom(peer.(*tg.InputPeerChannel))
full, err := s.tg.API().ChannelsGetFullChannel(ctx, &inputChannel)
if err != nil {
return nil, errors.Wrap(err, "get chat")
}
v := full.FullChat.(*tg.ChannelFull)
s.lg.Info("Got chat",
zap.String("name", name),
zap.Int64("id", v.ID),
zap.Int("participants", v.ParticipantsCount),
zap.Int("online", v.OnlineCount),
)
return v, nil
}

func (s Server) GetTelegramOnlineBadge(ctx context.Context, params oas.GetTelegramOnlineBadgeParams) (*oas.SVGHeaders, error) {
var count int
for _, name := range params.Groups {
full, err := s.fetchChannel(ctx, name)
if err != nil {
return nil, errors.Wrap(err, "get chat")
}
count += full.OnlineCount
}
var (
text = strconv.Itoa(count)
u = &url.URL{
Scheme: "https",
Host: "img.shields.io",
Path: generateBadgePath("online", text, "green"),
}
)
{
q := u.Query()
q.Set("logo", "telegram")
u.RawQuery = q.Encode()
}
return s.download(ctx, u)
}

func (s Server) GetTelegramBadge(ctx context.Context, params oas.GetTelegramBadgeParams) (*oas.SVGHeaders, error) {
channel, err := s.fetchChannel(ctx, params.GroupName)
if err != nil {
return nil, errors.Wrap(err, "get chat")
}
var (
title = params.Title.Or(params.GroupName)
text = strconv.Itoa(channel.ParticipantsCount)
u = &url.URL{
Scheme: "https",
Host: "img.shields.io",
Path: generateBadgePath(title, text, "179cde"),
}
)
{
q := u.Query()
q.Set("logo", "telegram")
u.RawQuery = q.Encode()
}
return s.download(ctx, u)
}
107 changes: 104 additions & 3 deletions internal/oas/oas_client_gen.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Loading

0 comments on commit 554d7a6

Please sign in to comment.