track user active state

This commit is contained in:
Artem Titoulenko 2021-12-18 17:10:00 -05:00
parent 06d3b84017
commit ed375e315c
4 changed files with 52 additions and 19 deletions

View file

@ -78,14 +78,19 @@ func (g *GenericServiceControls) HandleSNAC(ctx context.Context, db *bun.DB, sna
onlineSnac.Data.WriteString(uin)
onlineSnac.Data.WriteUint16(0) // warning level
user.Status = "active"
if err := user.Update(ctx, db); err != nil {
return ctx, errors.Wrap(err, "could not set user as active")
}
tlvs := []*oscar.TLV{
oscar.NewTLV(0x01, util.Dword(0x80)), // User Class
oscar.NewTLV(0x06, util.Dword(0x0001|0x0100)), // User Status (TODO: update status in DB)
oscar.NewTLV(0x0a, util.Dword(binary.BigEndian.Uint32([]byte(SRV_HOST)))), // External IP
oscar.NewTLV(0x0f, util.Dword(0x0)), // Idle Time (TODO: track idle time)
oscar.NewTLV(0x03, util.Dword(uint32(time.Now().Unix()))), // Client Signon Time
oscar.NewTLV(0x01e, util.Dword(0x0)), // Unknown value
oscar.NewTLV(0x05, util.Dword(uint32(time.Now().Unix()))), // Member since
oscar.NewTLV(0x01, util.Dword(0x80)), // User Class
oscar.NewTLV(0x06, util.Dword(0x0001|0x0100)), // User Status
oscar.NewTLV(0x0a, util.Dword(binary.BigEndian.Uint32([]byte(SRV_HOST)))), // External IP
oscar.NewTLV(0x0f, util.Dword(uint32(time.Since(user.LastActivityAt).Seconds()))), // Idle Time
oscar.NewTLV(0x03, util.Dword(uint32(time.Now().Unix()))), // Client Signon Time
oscar.NewTLV(0x01e, util.Dword(0x0)), // Unknown value
oscar.NewTLV(0x05, util.Dword(uint32(user.CreatedAt.Unix()))), // Member since
}
onlineSnac.Data.WriteUint16(uint16(len(tlvs)))

22
main.go
View file

@ -15,6 +15,7 @@ import (
"syscall"
"time"
"github.com/pkg/errors"
"github.com/uptrace/bun"
"github.com/uptrace/bun/dbfixture"
"github.com/uptrace/bun/dialect/sqlitedialect"
@ -68,7 +69,19 @@ func main() {
}
defer listener.Close()
handler := oscar.NewHandler(func(ctx context.Context, flap *oscar.FLAP) context.Context {
handleCloseFn := func(ctx context.Context, session *oscar.Session) {
log.Printf("%v disconnected", session.RemoteAddr())
user := models.UserFromContext(ctx)
if user != nil {
user.Status = "offline"
if err := user.Update(ctx, db); err != nil {
log.Print(errors.Wrap(err, "could not set user as active"))
}
}
}
handleFn := func(ctx context.Context, flap *oscar.FLAP) context.Context {
session, err := oscar.SessionFromContext(ctx)
if err != nil {
util.PanicIfError(err)
@ -76,6 +89,8 @@ func main() {
if user := models.UserFromContext(ctx); user != nil {
fmt.Printf("%s (%v) ->\n%+v\n", user.Username, session.RemoteAddr(), flap)
user.LastActivityAt = time.Now()
ctx = models.NewContextWithUser(ctx, user)
} else {
fmt.Printf("%v ->\n%+v\n", session.RemoteAddr(), flap)
}
@ -123,10 +138,13 @@ func main() {
}
} else if flap.Header.Channel == 4 {
session.Disconnect()
handleCloseFn(ctx, session)
}
return ctx
})
}
handler := oscar.NewHandler(handleFn, handleCloseFn)
RegisterService(0x17, &AuthorizationRegistrationService{})
RegisterService(0x01, &GenericServiceControls{})

View file

@ -3,18 +3,23 @@ package models
import (
"context"
"database/sql"
"time"
"github.com/pkg/errors"
"github.com/uptrace/bun"
)
type User struct {
bun.BaseModel `bun:"table:users"`
UIN int `bun:",pk,autoincrement"`
Email string `bun:",unique"`
Username string `bun:",unique"`
Password string
Cipher string
bun.BaseModel `bun:"table:users"`
UIN int `bun:",pk,autoincrement"`
Email string `bun:",unique"`
Username string `bun:",unique"`
Password string
Cipher string
CreatedAt time.Time `bun:",nullzero,notnull,default:current_timestamp"`
UpdatedAt time.Time `bun:",nullzero,notnull,default:current_timestamp"`
Status string
LastActivityAt time.Time `bin:"-"`
}
type userKey string

View file

@ -13,12 +13,17 @@ import (
)
type HandlerFunc func(context.Context, *FLAP) context.Context
type HandleCloseFn func(context.Context, *Session)
type Handler struct{ handle HandlerFunc }
type Handler struct {
handle HandlerFunc
handleClose HandleCloseFn
}
func NewHandler(fn HandlerFunc) *Handler {
func NewHandler(fn HandlerFunc, handleClose HandleCloseFn) *Handler {
return &Handler{
handle: fn,
handle: fn,
handleClose: handleClose,
}
}
@ -40,8 +45,8 @@ func (h *Handler) Handle(conn net.Conn) {
n, err := conn.Read(buf)
if err != nil && err != io.EOF {
if strings.Contains(err.Error(), "use of closed network connection") {
log.Printf("%v disconnected", conn.RemoteAddr())
session.Disconnect()
h.handleClose(ctx, session)
return
}