Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Mgmt API and unit test improvements #61

Merged
merged 2 commits into from
Aug 29, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
116 changes: 116 additions & 0 deletions api.yml
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,66 @@ paths:
'404':
description: User not found.

/user/{screenname}/account:
get:
summary: Get account details for a specific screen name.
description: Retrieve account details for a specific screen name.
parameters:
- name: screenname
in: path
description: User's AIM screen name or ICQ UIN.
required: true
type: string
responses:
'200':
description: Successful response containing account details
content:
application/json:
schema:
type: object
properties:
id:
type: string
description: User's unique identifier.
screen_name:
type: string
description: User's AIM screen name or ICQ UIN.
profile:
type: string
description: User's AIM profile HTML.
email_address:
type: string
description: User's email address
confirmed:
type: bool
description: User's account confirmation status
is_icq:
type: boolean
description: If true, indicates an ICQ user instead of an AIM user.
'404':
description: User not found.

/user/{screenname}/icon:
get:
summary: Get AIM buddy icon for a screen name
description: Retrieve account buddy icon for a specific screen name.
parameters:
- name: screenname
in: path
description: User's AIM screen name or ICQ UIN.
required: true
type: string
responses:
'200':
description: Successful response containing buddy icon bytes
content:
image/gif:
schema:
type: string
format: binary
'404':
description: User not found, or user has no buddy icon

/session:
get:
summary: Get active sessions
Expand All @@ -98,10 +158,66 @@ paths:
screen_name:
type: string
description: User's AIM screen name or ICQ UIN.
online_seconds:
type: float
description: Number of seconds this user session has been online.
away_message:
type: string
description: User's AIM away message HTML. Empty if the user is not away.
idle_seconds:
type: float
description: Number of seconds this user session has been idle. 0 if not idle.
is_icq:
type: boolean
description: If true, indicates an ICQ user instead of an AIM user.

/session/{screenname}:
get:
summary: Get active sessions for a given screen name or UIN.
description: Retrieve a list of active sessions of a specific logged in user.
parameters:
- name: screenname
in: path
description: User's AIM screen name or ICQ UIN.
required: true
type: string
responses:
'200':
description: Successful response containing a list of active sessions for the given screen name
content:
application/json:
schema:
type: object
properties:
count:
type: integer
description: The number of active sessions.
sessions:
type: array
items:
type: object
properties:
id:
type: string
description: User's unique identifier.
screen_name:
type: string
description: User's AIM screen name or ICQ UIN.
online_seconds:
type: float
description: Number of seconds this user session has been online.
away_message:
type: string
description: User's AIM away message HTML. Empty if the user is not away.
idle_seconds:
type: float
description: Number of seconds this user session has been idle. 0 if not idle.
is_icq:
type: boolean
description: If true, indicates an ICQ user instead of an AIM user.
'404':
description: User not found.

/user/password:
put:
summary: Set a user's password
Expand Down
2 changes: 1 addition & 1 deletion cmd/server/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@ func main() {
wg.Add(7)

go func() {
http.StartManagementAPI(cfg, feedbagStore, sessionManager, feedbagStore, feedbagStore, chatSessionManager, sessionManager, logger)
http.StartManagementAPI(cfg, feedbagStore, sessionManager, feedbagStore, feedbagStore, chatSessionManager, sessionManager, feedbagStore, feedbagStore, feedbagStore, feedbagStore, logger)
wg.Done()
}()
go func(logger *slog.Logger) {
Expand Down
61 changes: 2 additions & 59 deletions foodgroup/buddy.go
Original file line number Diff line number Diff line change
@@ -1,10 +1,7 @@
package foodgroup

import (
"bytes"
"context"
"errors"
"strconv"

"github.com/mk6i/retro-aim-server/state"
"github.com/mk6i/retro-aim-server/wire"
Expand Down Expand Up @@ -87,7 +84,7 @@ func (s BuddyService) DelBuddies(_ context.Context, sess *state.Session, inBody
// buddy icons, warning levels, invisibility status, etc.
func (s BuddyService) UnicastBuddyArrived(ctx context.Context, from *state.Session, to *state.Session) error {
userInfo := from.TLVUserInfo()
icon, err := getBuddyIconRefFromFeedbag(from, s.feedbagManager)
icon, err := s.feedbagManager.BuddyIconRefByName(from.IdentScreenName())
switch {
case err != nil:
return err
Expand Down Expand Up @@ -122,7 +119,7 @@ func (s BuddyService) BroadcastBuddyArrived(ctx context.Context, sess *state.Ses
recipients = append(recipients, legacyUsers...)

userInfo := sess.TLVUserInfo()
icon, err := getBuddyIconRefFromFeedbag(sess, s.feedbagManager)
icon, err := s.feedbagManager.BuddyIconRefByName(sess.IdentScreenName())
switch {
case err != nil:
return err
Expand All @@ -143,60 +140,6 @@ func (s BuddyService) BroadcastBuddyArrived(ctx context.Context, sess *state.Ses
return nil
}

// getBuddyIconRefFromFeedbag retrieves a reference to the user's buddy icon
// from their feedbag. If it exists, the buddy icon is the feedbag item of
// class wire.FeedbagClassIdBart with BART type wire.BARTTypesBuddyIcon.
func getBuddyIconRefFromFeedbag(sess *state.Session, feedbagManager FeedbagManager) (*wire.BARTID, error) {
items, err := feedbagManager.Feedbag(sess.IdentScreenName())
if err != nil {
return nil, err
}

for _, item := range items {
if item.ClassID != wire.FeedbagClassIdBart {
continue
}
bartType, err := extractBARTItemType(item)
if err != nil {
return nil, err
}
if bartType != wire.BARTTypesBuddyIcon {
continue
}
b, hasBuf := item.Slice(wire.FeedbagAttributesBartInfo)
if !hasBuf {
return nil, errors.New("unable to extract icon payload")
}
bartInfo := wire.BARTInfo{}
if err := wire.UnmarshalBE(&bartInfo, bytes.NewBuffer(b)); err != nil {
return nil, err
}
return &wire.BARTID{
Type: bartType,
BARTInfo: wire.BARTInfo{
Flags: bartInfo.Flags,
Hash: bartInfo.Hash,
},
}, nil
}

return nil, nil
}

// extractBARTItemType gets the BART type for item, which is stored in the
// "name" field.
func extractBARTItemType(item wire.FeedbagItem) (uint16, error) {
var bartType uint16
// Feedbag items of type wire.FeedbagClassIdBart store the BART type in the
// name field.
if bt, err := strconv.ParseUint(item.Name, 10, 16); err != nil {
return 0, err
} else {
bartType = uint16(bt)
}
return bartType, nil
}

func (s BuddyService) BroadcastBuddyDeparted(ctx context.Context, sess *state.Session) error {
recipients, err := s.feedbagManager.AdjacentUsers(sess.IdentScreenName())
if err != nil {
Expand Down
69 changes: 39 additions & 30 deletions foodgroup/buddy_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -106,9 +106,10 @@ func TestBuddyService_AddBuddies(t *testing.T) {
},
},
feedbagManagerParams: feedbagManagerParams{
feedbagParams: feedbagParams{
buddyIconRefByNameParams: buddyIconRefByNameParams{
{
screenName: state.NewIdentScreenName("buddy_1_online"),
result: nil,
},
},
},
Expand Down Expand Up @@ -159,6 +160,11 @@ func TestBuddyService_AddBuddies(t *testing.T) {
}

feedbagManager := newMockFeedbagManager(t)
for _, params := range tt.mockParams.feedbagManagerParams.buddyIconRefByNameParams {
feedbagManager.EXPECT().
BuddyIconRefByName(params.screenName).
Return(params.result, params.err)
}
for _, params := range tt.mockParams.feedbagParams {
feedbagManager.EXPECT().
Feedbag(params.screenName).
Expand Down Expand Up @@ -266,6 +272,12 @@ func TestBuddyService_BroadcastBuddyArrived(t *testing.T) {
results: []wire.FeedbagItem{},
},
},
buddyIconRefByNameParams: buddyIconRefByNameParams{
{
screenName: state.NewIdentScreenName("user_screen_name"),
result: nil,
},
},
},
messageRelayerParams: messageRelayerParams{
relayToScreenNamesParams: relayToScreenNamesParams{
Expand Down Expand Up @@ -307,28 +319,14 @@ func TestBuddyService_BroadcastBuddyArrived(t *testing.T) {
users: []state.IdentScreenName{state.NewIdentScreenName("friend1")},
},
},
feedbagParams: feedbagParams{
buddyIconRefByNameParams: buddyIconRefByNameParams{
{
screenName: state.NewIdentScreenName("user_screen_name"),
results: []wire.FeedbagItem{
{
ClassID: wire.FeedbagClassIdBuddy,
Name: "friend10",
},
{
ClassID: wire.FeedbagClassIdBart,
Name: strconv.Itoa(int(wire.BARTTypesBadgeUrl)),
},
{
ClassID: wire.FeedbagClassIdBart,
Name: strconv.Itoa(int(wire.BARTTypesBuddyIcon)),
TLVLBlock: wire.TLVLBlock{
TLVList: wire.TLVList{
wire.NewTLV(wire.FeedbagAttributesBartInfo, wire.BARTInfo{
Hash: []byte{'t', 'h', 'e', 'h', 'a', 's', 'h'},
}),
},
},
result: &wire.BARTID{
Type: wire.BARTTypesBuddyIcon,
BARTInfo: wire.BARTInfo{
Flags: wire.BARTFlagsKnown,
Hash: []byte{'t', 'h', 'e', 'h', 'a', 's', 'h'},
},
},
},
Expand Down Expand Up @@ -379,10 +377,10 @@ func TestBuddyService_BroadcastBuddyArrived(t *testing.T) {
AdjacentUsers(params.screenName).
Return(params.users, params.err)
}
for _, params := range tc.mockParams.feedbagManagerParams.feedbagParams {
for _, params := range tc.mockParams.feedbagManagerParams.buddyIconRefByNameParams {
feedbagManager.EXPECT().
Feedbag(params.screenName).
Return(params.results, nil)
BuddyIconRefByName(params.screenName).
Return(params.result, params.err)
}
messageRelayer := newMockMessageRelayer(t)
for _, params := range tc.mockParams.messageRelayerParams.relayToScreenNamesParams {
Expand Down Expand Up @@ -566,10 +564,10 @@ func TestBuddyService_UnicastBuddyArrived(t *testing.T) {
destSession: newTestSession("dest_screen_name"),
mockParams: mockParams{
feedbagManagerParams: feedbagManagerParams{
feedbagParams: feedbagParams{
buddyIconRefByNameParams: buddyIconRefByNameParams{
{
screenName: state.NewIdentScreenName("src_screen_name"),
results: []wire.FeedbagItem{},
result: nil,
},
},
},
Expand Down Expand Up @@ -623,6 +621,18 @@ func TestBuddyService_UnicastBuddyArrived(t *testing.T) {
},
},
},
buddyIconRefByNameParams: buddyIconRefByNameParams{
{
screenName: state.NewIdentScreenName("src_screen_name"),
result: &wire.BARTID{
Type: wire.BARTTypesBuddyIcon,
BARTInfo: wire.BARTInfo{
Flags: wire.BARTFlagsKnown,
Hash: []byte{'t', 'h', 'e', 'h', 'a', 's', 'h'},
},
},
},
},
},
messageRelayerParams: messageRelayerParams{
relayToScreenNameParams: relayToScreenNameParams{
Expand Down Expand Up @@ -656,17 +666,16 @@ func TestBuddyService_UnicastBuddyArrived(t *testing.T) {
for _, tc := range cases {
t.Run(tc.name, func(t *testing.T) {
feedbagManager := newMockFeedbagManager(t)
for _, params := range tc.mockParams.feedbagManagerParams.feedbagParams {
for _, params := range tc.mockParams.feedbagManagerParams.buddyIconRefByNameParams {
feedbagManager.EXPECT().
Feedbag(params.screenName).
Return(params.results, nil)
BuddyIconRefByName(params.screenName).
Return(params.result, params.err)
}
messageRelayer := newMockMessageRelayer(t)
for _, params := range tc.mockParams.messageRelayerParams.relayToScreenNameParams {
messageRelayer.EXPECT().
RelayToScreenName(mock.Anything, params.screenName, params.message)
}

svc := NewBuddyService(messageRelayer, feedbagManager, nil)

err := svc.UnicastBuddyArrived(nil, tc.sourceSession, tc.destSession)
Expand Down
Loading
Loading