From 0c75d75e24bc94fdb9f08c65aa7c68f9f76c066b Mon Sep 17 00:00:00 2001 From: Sergey Chubaryan Date: Tue, 6 Aug 2024 22:15:57 +0300 Subject: [PATCH 1/5] improved random string generation --- main.go | 4 +- src/services/shortlink_service.go | 29 ++------- src/utils/random.go | 70 ++++++++++++++++++++++ {args_parser => utils/args_parser}/args.go | 0 {config => utils/config}/config.go | 0 {config => utils/config}/config_test.go | 0 {config => utils/config}/new.go | 0 {config => utils/config}/parser.go | 0 8 files changed, 78 insertions(+), 25 deletions(-) create mode 100644 src/utils/random.go rename {args_parser => utils/args_parser}/args.go (100%) rename {config => utils/config}/config.go (100%) rename {config => utils/config}/config_test.go (100%) rename {config => utils/config}/new.go (100%) rename {config => utils/config}/parser.go (100%) diff --git a/main.go b/main.go index 1c7d398..36c1d6d 100644 --- a/main.go +++ b/main.go @@ -1,8 +1,6 @@ package main import ( - "backend/args_parser" - "backend/config" "backend/logger" "backend/src/handlers" "backend/src/middleware" @@ -10,6 +8,8 @@ import ( "backend/src/repo" "backend/src/services" "backend/src/utils" + "backend/utils/args_parser" + "backend/utils/config" "crypto/rsa" "crypto/x509" "database/sql" diff --git a/src/services/shortlink_service.go b/src/services/shortlink_service.go index d3f2469..9901b25 100644 --- a/src/services/shortlink_service.go +++ b/src/services/shortlink_service.go @@ -2,10 +2,8 @@ package services import ( "backend/src/repo" + "backend/src/utils" "fmt" - "math/rand" - "strings" - "time" ) type ShortlinkService interface { @@ -20,33 +18,18 @@ type NewShortlinkServiceParams struct { func NewShortlinkSevice(params NewShortlinkServiceParams) ShortlinkService { return &shortlinkService{ - cache: params.Cache, + randomUtil: *utils.NewRand(), + cache: params.Cache, } } type shortlinkService struct { - cache repo.Cache[string, string] -} - -func (s *shortlinkService) randomStr() string { - src := rand.NewSource(time.Now().UnixMicro()) - randGen := rand.New(src) - - builder := strings.Builder{} - for i := 0; i < 9; i++ { - offset := 0x41 - if randGen.Int()%2 == 1 { - offset = 0x61 - } - - byte := offset + (randGen.Int() % 26) - builder.WriteRune(rune(byte)) - } - return builder.String() + randomUtil utils.RandomUtil + cache repo.Cache[string, string] } func (s *shortlinkService) CreateLink(in string) (string, error) { - str := s.randomStr() + str := s.randomUtil.RandomID(10, utils.CharsetAll) s.cache.Set(str, in, 7*24*60*60) return str, nil } diff --git a/src/utils/random.go b/src/utils/random.go new file mode 100644 index 0000000..df07126 --- /dev/null +++ b/src/utils/random.go @@ -0,0 +1,70 @@ +package utils + +import ( + "math/rand" + "strings" + "time" +) + +type Charset int + +const ( + CharsetAll Charset = iota + CharsetLettersLower + CharsetLettersUpper + CharsetLetters + CharsetNumeric +) + +type charsetPart struct { + Offset int + Size int +} + +var charsets = map[Charset][]charsetPart{} + +func NewRand() *RandomUtil { + charsetLettersLower := charsetPart{ //CharsetLettersLower + Offset: 0x41, + Size: 26, + } + + charsetLettersUpper := charsetPart{ //CharsetLettersUpper + Offset: 0x61, + Size: 26, + } + + charsetNumeric := charsetPart{ //CharsetLettersNumeric + Offset: 0x30, + Size: 10, + } + + charsets = map[Charset][]charsetPart{ + CharsetNumeric: {charsetNumeric}, + CharsetLettersLower: {charsetLettersLower}, + CharsetLettersUpper: {charsetLettersUpper}, + CharsetLetters: {charsetLettersLower, charsetLettersUpper}, + CharsetAll: {charsetLettersLower, charsetLettersUpper, charsetNumeric}, + } + + return &RandomUtil{} +} + +type RandomUtil struct{} + +func (r *RandomUtil) RandomID(outputLenght int, charset Charset) string { + src := rand.NewSource(time.Now().UnixMicro()) + randGen := rand.New(src) + + charsetData := charsets[charset] + + builder := strings.Builder{} + for i := 0; i < outputLenght; i++ { + charsetIdx := randGen.Int() % len(charsetData) + charsetPart := charsetData[charsetIdx] + + byte := charsetPart.Offset + (randGen.Int() % charsetPart.Size) + builder.WriteRune(rune(byte)) + } + return builder.String() +} diff --git a/args_parser/args.go b/utils/args_parser/args.go similarity index 100% rename from args_parser/args.go rename to utils/args_parser/args.go diff --git a/config/config.go b/utils/config/config.go similarity index 100% rename from config/config.go rename to utils/config/config.go diff --git a/config/config_test.go b/utils/config/config_test.go similarity index 100% rename from config/config_test.go rename to utils/config/config_test.go diff --git a/config/new.go b/utils/config/new.go similarity index 100% rename from config/new.go rename to utils/config/new.go diff --git a/config/parser.go b/utils/config/parser.go similarity index 100% rename from config/parser.go rename to utils/config/parser.go From 133744eb1664d90b119fb81b2b446eaaddede686 Mon Sep 17 00:00:00 2001 From: Sergey Chubaryan Date: Thu, 8 Aug 2024 19:34:36 +0300 Subject: [PATCH 2/5] code reorganisation --- .gitignore | 8 +++++- main.go | 28 +++++++++---------- {utils => src}/args_parser/args.go | 0 {utils => src}/config/config.go | 0 {utils => src}/config/config_test.go | 0 {utils => src}/config/new.go | 0 {utils => src}/config/parser.go | 0 src/{ => core}/models/action_token.go | 0 src/{ => core}/models/user.go | 0 src/{repo => core/repos}/action_token.go | 4 +-- src/{repo => core/repos}/cache_inmem.go | 2 +- src/{repo => core/repos}/email_repo.go | 2 +- src/{repo => core/repos}/user_repo.go | 4 +-- src/{ => core}/services/shortlink_service.go | 8 +++--- src/{ => core}/services/user_service.go | 14 +++++----- src/{ => core}/utils/jwt.go | 0 src/{ => core}/utils/password.go | 0 src/{ => core}/utils/random.go | 0 src/leader_elector/elector.go | 25 +++++++++++++++++ {logger => src/logger}/event.go | 0 {logger => src/logger}/logger.go | 0 {logger => src/logger}/new.go | 0 src/{ => server}/handlers/dummy_handler.go | 0 .../handlers/shortlink_handlers.go | 2 +- .../handlers/user_create_handler.go | 2 +- .../handlers/user_login_handler.go | 2 +- src/{ => server}/middleware/auth.go | 2 +- src/{ => server}/middleware/request_log.go | 2 +- 28 files changed, 68 insertions(+), 37 deletions(-) rename {utils => src}/args_parser/args.go (100%) rename {utils => src}/config/config.go (100%) rename {utils => src}/config/config_test.go (100%) rename {utils => src}/config/new.go (100%) rename {utils => src}/config/parser.go (100%) rename src/{ => core}/models/action_token.go (100%) rename src/{ => core}/models/user.go (100%) rename src/{repo => core/repos}/action_token.go (97%) rename src/{repo => core/repos}/cache_inmem.go (98%) rename src/{repo => core/repos}/email_repo.go (98%) rename src/{repo => core/repos}/user_repo.go (98%) rename src/{ => core}/services/shortlink_service.go (85%) rename src/{ => core}/services/user_service.go (95%) rename src/{ => core}/utils/jwt.go (100%) rename src/{ => core}/utils/password.go (100%) rename src/{ => core}/utils/random.go (100%) create mode 100644 src/leader_elector/elector.go rename {logger => src/logger}/event.go (100%) rename {logger => src/logger}/logger.go (100%) rename {logger => src/logger}/new.go (100%) rename src/{ => server}/handlers/dummy_handler.go (100%) rename src/{ => server}/handlers/shortlink_handlers.go (97%) rename src/{ => server}/handlers/user_create_handler.go (97%) rename src/{ => server}/handlers/user_login_handler.go (96%) rename src/{ => server}/middleware/auth.go (94%) rename src/{ => server}/middleware/request_log.go (97%) diff --git a/.gitignore b/.gitignore index 64ae7f3..1760a31 100644 --- a/.gitignore +++ b/.gitignore @@ -22,4 +22,10 @@ go.work go.work.sum # env file -.env \ No newline at end of file +.env + +.run + +# temporary +coworker/ +webapp/ \ No newline at end of file diff --git a/main.go b/main.go index 36c1d6d..a09b4db 100644 --- a/main.go +++ b/main.go @@ -1,15 +1,15 @@ package main import ( - "backend/logger" - "backend/src/handlers" - "backend/src/middleware" - "backend/src/models" - "backend/src/repo" - "backend/src/services" - "backend/src/utils" - "backend/utils/args_parser" - "backend/utils/config" + "backend/src/args_parser" + "backend/src/config" + "backend/src/core/models" + "backend/src/core/repos" + "backend/src/core/services" + "backend/src/core/utils" + "backend/src/logger" + "backend/src/server/handlers" + "backend/src/server/middleware" "crypto/rsa" "crypto/x509" "database/sql" @@ -75,10 +75,10 @@ func main() { jwtUtil := utils.NewJwtUtil(key) passwordUtil := utils.NewPasswordUtil() - userRepo := repo.NewUserRepo(sqlDb) - userCache := repo.NewCacheInmem[string, models.UserDTO](60 * 60) - emailRepo := repo.NewEmailRepo() - actionTokenRepo := repo.NewActionTokenRepo(sqlDb) + userRepo := repos.NewUserRepo(sqlDb) + userCache := repos.NewCacheInmem[string, models.UserDTO](60 * 60) + emailRepo := repos.NewEmailRepo() + actionTokenRepo := repos.NewActionTokenRepo(sqlDb) userService := services.NewUserService( services.UserServiceDeps{ @@ -92,7 +92,7 @@ func main() { ) linkService := services.NewShortlinkSevice( services.NewShortlinkServiceParams{ - Cache: repo.NewCacheInmem[string, string](7 * 24 * 60 * 60), + Cache: repos.NewCacheInmem[string, string](7 * 24 * 60 * 60), }, ) diff --git a/utils/args_parser/args.go b/src/args_parser/args.go similarity index 100% rename from utils/args_parser/args.go rename to src/args_parser/args.go diff --git a/utils/config/config.go b/src/config/config.go similarity index 100% rename from utils/config/config.go rename to src/config/config.go diff --git a/utils/config/config_test.go b/src/config/config_test.go similarity index 100% rename from utils/config/config_test.go rename to src/config/config_test.go diff --git a/utils/config/new.go b/src/config/new.go similarity index 100% rename from utils/config/new.go rename to src/config/new.go diff --git a/utils/config/parser.go b/src/config/parser.go similarity index 100% rename from utils/config/parser.go rename to src/config/parser.go diff --git a/src/models/action_token.go b/src/core/models/action_token.go similarity index 100% rename from src/models/action_token.go rename to src/core/models/action_token.go diff --git a/src/models/user.go b/src/core/models/user.go similarity index 100% rename from src/models/user.go rename to src/core/models/user.go diff --git a/src/repo/action_token.go b/src/core/repos/action_token.go similarity index 97% rename from src/repo/action_token.go rename to src/core/repos/action_token.go index 453a4ab..df2c26d 100644 --- a/src/repo/action_token.go +++ b/src/core/repos/action_token.go @@ -1,7 +1,7 @@ -package repo +package repos import ( - "backend/src/models" + "backend/src/core/models" "context" "database/sql" ) diff --git a/src/repo/cache_inmem.go b/src/core/repos/cache_inmem.go similarity index 98% rename from src/repo/cache_inmem.go rename to src/core/repos/cache_inmem.go index 7b27175..4b834ca 100644 --- a/src/repo/cache_inmem.go +++ b/src/core/repos/cache_inmem.go @@ -1,4 +1,4 @@ -package repo +package repos import ( "sync" diff --git a/src/repo/email_repo.go b/src/core/repos/email_repo.go similarity index 98% rename from src/repo/email_repo.go rename to src/core/repos/email_repo.go index 9dd6733..e1eb0b4 100644 --- a/src/repo/email_repo.go +++ b/src/core/repos/email_repo.go @@ -1,4 +1,4 @@ -package repo +package repos import ( "strings" diff --git a/src/repo/user_repo.go b/src/core/repos/user_repo.go similarity index 98% rename from src/repo/user_repo.go rename to src/core/repos/user_repo.go index c2651bd..d64db63 100644 --- a/src/repo/user_repo.go +++ b/src/core/repos/user_repo.go @@ -1,7 +1,7 @@ -package repo +package repos import ( - "backend/src/models" + "backend/src/core/models" "context" "database/sql" "errors" diff --git a/src/services/shortlink_service.go b/src/core/services/shortlink_service.go similarity index 85% rename from src/services/shortlink_service.go rename to src/core/services/shortlink_service.go index 9901b25..198690a 100644 --- a/src/services/shortlink_service.go +++ b/src/core/services/shortlink_service.go @@ -1,8 +1,8 @@ package services import ( - "backend/src/repo" - "backend/src/utils" + "backend/src/core/repos" + "backend/src/core/utils" "fmt" ) @@ -13,7 +13,7 @@ type ShortlinkService interface { type NewShortlinkServiceParams struct { Endpoint string - Cache repo.Cache[string, string] + Cache repos.Cache[string, string] } func NewShortlinkSevice(params NewShortlinkServiceParams) ShortlinkService { @@ -25,7 +25,7 @@ func NewShortlinkSevice(params NewShortlinkServiceParams) ShortlinkService { type shortlinkService struct { randomUtil utils.RandomUtil - cache repo.Cache[string, string] + cache repos.Cache[string, string] } func (s *shortlinkService) CreateLink(in string) (string, error) { diff --git a/src/services/user_service.go b/src/core/services/user_service.go similarity index 95% rename from src/services/user_service.go rename to src/core/services/user_service.go index f8e8433..3faf7fe 100644 --- a/src/services/user_service.go +++ b/src/core/services/user_service.go @@ -1,9 +1,9 @@ package services import ( - "backend/src/models" - "backend/src/repo" - "backend/src/utils" + "backend/src/core/models" + "backend/src/core/repos" + "backend/src/core/utils" "context" "fmt" @@ -32,10 +32,10 @@ func NewUserService(deps UserServiceDeps) UserService { type UserServiceDeps struct { Jwt utils.JwtUtil Password utils.PasswordUtil - UserRepo repo.UserRepo - UserCache repo.Cache[string, models.UserDTO] - EmailRepo repo.EmailRepo - ActionTokenRepo repo.ActionTokenRepo + UserRepo repos.UserRepo + UserCache repos.Cache[string, models.UserDTO] + EmailRepo repos.EmailRepo + ActionTokenRepo repos.ActionTokenRepo } type userService struct { diff --git a/src/utils/jwt.go b/src/core/utils/jwt.go similarity index 100% rename from src/utils/jwt.go rename to src/core/utils/jwt.go diff --git a/src/utils/password.go b/src/core/utils/password.go similarity index 100% rename from src/utils/password.go rename to src/core/utils/password.go diff --git a/src/utils/random.go b/src/core/utils/random.go similarity index 100% rename from src/utils/random.go rename to src/core/utils/random.go diff --git a/src/leader_elector/elector.go b/src/leader_elector/elector.go new file mode 100644 index 0000000..4c9ac94 --- /dev/null +++ b/src/leader_elector/elector.go @@ -0,0 +1,25 @@ +package leader_elector + +import ( + "context" + "database/sql" +) + +func Lock(ctx context.Context, db *sql.DB, lockName, id string) error { + query := ` + update locks (id) + set id = $1 + where name == lockName and timestamp < $1 returning id + on conflict + insert into locks(id, name) values($1, $2);` + + row := db.QueryRowContext(ctx, query, id) + + result := "" + err := row.Scan(&result) + if err != nil { + return err + } + + return nil +} diff --git a/logger/event.go b/src/logger/event.go similarity index 100% rename from logger/event.go rename to src/logger/event.go diff --git a/logger/logger.go b/src/logger/logger.go similarity index 100% rename from logger/logger.go rename to src/logger/logger.go diff --git a/logger/new.go b/src/logger/new.go similarity index 100% rename from logger/new.go rename to src/logger/new.go diff --git a/src/handlers/dummy_handler.go b/src/server/handlers/dummy_handler.go similarity index 100% rename from src/handlers/dummy_handler.go rename to src/server/handlers/dummy_handler.go diff --git a/src/handlers/shortlink_handlers.go b/src/server/handlers/shortlink_handlers.go similarity index 97% rename from src/handlers/shortlink_handlers.go rename to src/server/handlers/shortlink_handlers.go index f228e8e..44e200e 100644 --- a/src/handlers/shortlink_handlers.go +++ b/src/server/handlers/shortlink_handlers.go @@ -1,7 +1,7 @@ package handlers import ( - "backend/src/services" + "backend/src/core/services" "encoding/json" "fmt" "net/url" diff --git a/src/handlers/user_create_handler.go b/src/server/handlers/user_create_handler.go similarity index 97% rename from src/handlers/user_create_handler.go rename to src/server/handlers/user_create_handler.go index b50f336..28ad72c 100644 --- a/src/handlers/user_create_handler.go +++ b/src/server/handlers/user_create_handler.go @@ -1,7 +1,7 @@ package handlers import ( - "backend/src/services" + "backend/src/core/services" "encoding/json" "github.com/gin-gonic/gin" diff --git a/src/handlers/user_login_handler.go b/src/server/handlers/user_login_handler.go similarity index 96% rename from src/handlers/user_login_handler.go rename to src/server/handlers/user_login_handler.go index 2a273e4..00eec5d 100644 --- a/src/handlers/user_login_handler.go +++ b/src/server/handlers/user_login_handler.go @@ -1,7 +1,7 @@ package handlers import ( - "backend/src/services" + "backend/src/core/services" "encoding/json" "github.com/gin-gonic/gin" diff --git a/src/middleware/auth.go b/src/server/middleware/auth.go similarity index 94% rename from src/middleware/auth.go rename to src/server/middleware/auth.go index 9392816..78419a0 100644 --- a/src/middleware/auth.go +++ b/src/server/middleware/auth.go @@ -1,7 +1,7 @@ package middleware import ( - "backend/src/services" + "backend/src/core/services" "fmt" "github.com/gin-gonic/gin" diff --git a/src/middleware/request_log.go b/src/server/middleware/request_log.go similarity index 97% rename from src/middleware/request_log.go rename to src/server/middleware/request_log.go index 5f79b58..889d75f 100644 --- a/src/middleware/request_log.go +++ b/src/server/middleware/request_log.go @@ -1,7 +1,7 @@ package middleware import ( - "backend/logger" + "backend/src/logger" "time" "github.com/gin-gonic/gin" From 2f74e51a9d3cc0a6b91da4182db88483842b004e Mon Sep 17 00:00:00 2001 From: Sergey Chubaryan Date: Thu, 8 Aug 2024 19:42:20 +0300 Subject: [PATCH 3/5] structure improvements, added makefile --- .gitignore | 3 +++ makefile | 4 ++++ {config_example => misc}/config.yaml | 0 {config_example => misc}/jwt_signing_key | 0 db_init.sql => sql/db_init.sql | 0 5 files changed, 7 insertions(+) create mode 100644 makefile rename {config_example => misc}/config.yaml (100%) rename {config_example => misc}/jwt_signing_key (100%) rename db_init.sql => sql/db_init.sql (100%) diff --git a/.gitignore b/.gitignore index 1760a31..fec6d12 100644 --- a/.gitignore +++ b/.gitignore @@ -21,6 +21,9 @@ go.work go.work.sum +# Binary dir +.build/ + # env file .env diff --git a/makefile b/makefile new file mode 100644 index 0000000..0b351d6 --- /dev/null +++ b/makefile @@ -0,0 +1,4 @@ +all: release + +release: + go build -o ./.build/release/backend main.go \ No newline at end of file diff --git a/config_example/config.yaml b/misc/config.yaml similarity index 100% rename from config_example/config.yaml rename to misc/config.yaml diff --git a/config_example/jwt_signing_key b/misc/jwt_signing_key similarity index 100% rename from config_example/jwt_signing_key rename to misc/jwt_signing_key diff --git a/db_init.sql b/sql/db_init.sql similarity index 100% rename from db_init.sql rename to sql/db_init.sql From 19297b331ec9db1a3f552a991b155e76835fd56a Mon Sep 17 00:00:00 2001 From: Sergey Chubaryan Date: Sun, 11 Aug 2024 23:50:19 +0300 Subject: [PATCH 4/5] dockerfile fix --- dockerfile | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/dockerfile b/dockerfile index e1d6c8a..daf5c37 100644 --- a/dockerfile +++ b/dockerfile @@ -8,6 +8,7 @@ RUN go mod download && go mod verify EXPOSE 8080 COPY . . -RUN go build -v -o /usr/local/bin/app ./... +RUN go build -v -o ./app . +RUN chmod +x ./app -CMD ["app"] \ No newline at end of file +CMD ["./app", "-c", "./misc/config.yaml"] \ No newline at end of file From 17b09703642c8c484607aee84c41a0ed65e0edc9 Mon Sep 17 00:00:00 2001 From: Sergey Chubaryan Date: Fri, 16 Aug 2024 00:37:15 +0300 Subject: [PATCH 5/5] added long pooling --- main.go | 6 +++ src/client_notifier/event.go | 12 +++++ src/client_notifier/notifier.go | 57 +++++++++++++++++++++ src/server/handlers/long_pooling_handler.go | 27 ++++++++++ src/server/utils/user.go | 14 +++++ 5 files changed, 116 insertions(+) create mode 100644 src/client_notifier/event.go create mode 100644 src/client_notifier/notifier.go create mode 100644 src/server/handlers/long_pooling_handler.go create mode 100644 src/server/utils/user.go diff --git a/main.go b/main.go index a09b4db..40ac6e1 100644 --- a/main.go +++ b/main.go @@ -2,6 +2,7 @@ package main import ( "backend/src/args_parser" + "backend/src/client_notifier" "backend/src/config" "backend/src/core/models" "backend/src/core/repos" @@ -80,6 +81,8 @@ func main() { emailRepo := repos.NewEmailRepo() actionTokenRepo := repos.NewActionTokenRepo(sqlDb) + clientNotifier := client_notifier.NewBasicNotifier() + userService := services.NewUserService( services.UserServiceDeps{ Jwt: jwtUtil, @@ -116,6 +119,9 @@ func main() { dummyGroup.Use(middleware.NewAuthMiddleware(userService)) dummyGroup.GET("/", handlers.NewDummyHandler()) + lpGroup := r.Group("/pooling") + lpGroup.GET("/", handlers.NewLongPoolingHandler(clientNotifier)) + listenAddr := fmt.Sprintf(":%d", conf.GetPort()) logger.Log().Msgf("server listening on %s", listenAddr) diff --git a/src/client_notifier/event.go b/src/client_notifier/event.go new file mode 100644 index 0000000..f577329 --- /dev/null +++ b/src/client_notifier/event.go @@ -0,0 +1,12 @@ +package client_notifier + +type Event struct { + Type EventType + Data []byte +} + +type EventType string + +const ( + EventTypeEmailConfirmed EventType = "event_email_confirmed" +) diff --git a/src/client_notifier/notifier.go b/src/client_notifier/notifier.go new file mode 100644 index 0000000..cd03efc --- /dev/null +++ b/src/client_notifier/notifier.go @@ -0,0 +1,57 @@ +package client_notifier + +import "sync" + +type ClientNotifier interface { + RegisterClient(id string) <-chan Event + UnregisterClient(id string) + NotifyClient(id string, e Event) +} + +type client struct { + id string + eventChan chan Event +} + +func NewBasicNotifier() ClientNotifier { + return &basicNotifier{ + m: &sync.RWMutex{}, + clients: map[string]client{}, + } +} + +type basicNotifier struct { + m *sync.RWMutex + clients map[string]client +} + +func (p *basicNotifier) RegisterClient(id string) <-chan Event { + p.m.Lock() + defer p.m.Unlock() + + eventChan := make(chan Event) + p.clients[id] = client{ + id: id, + eventChan: eventChan, + } + + return eventChan +} + +func (p *basicNotifier) UnregisterClient(id string) { + p.m.Lock() + defer p.m.Unlock() + + delete(p.clients, id) +} + +func (p *basicNotifier) NotifyClient(id string, e Event) { + p.m.RLock() + defer p.m.RUnlock() + + client, ok := p.clients[id] + if !ok { + return + } + client.eventChan <- e +} diff --git a/src/server/handlers/long_pooling_handler.go b/src/server/handlers/long_pooling_handler.go new file mode 100644 index 0000000..332436e --- /dev/null +++ b/src/server/handlers/long_pooling_handler.go @@ -0,0 +1,27 @@ +package handlers + +import ( + "backend/src/client_notifier" + "backend/src/server/utils" + + "github.com/gin-gonic/gin" +) + +func NewLongPoolingHandler(notifier client_notifier.ClientNotifier) gin.HandlerFunc { + return func(c *gin.Context) { + user := utils.GetUserFromRequest(c) + if user == nil { + c.Data(403, "plain/text", []byte("Unauthorized")) + return + } + + eventChan := notifier.RegisterClient(user.Id) + + select { + case <-c.Done(): + notifier.UnregisterClient(user.Id) + case event := <-eventChan: + c.Data(200, "application/json", event.Data) + } + } +} diff --git a/src/server/utils/user.go b/src/server/utils/user.go new file mode 100644 index 0000000..0f6bb32 --- /dev/null +++ b/src/server/utils/user.go @@ -0,0 +1,14 @@ +package utils + +import ( + "backend/src/core/models" + + "github.com/gin-gonic/gin" +) + +func GetUserFromRequest(c *gin.Context) *models.UserDTO { + if user, ok := c.Get("user"); ok { + return user.(*models.UserDTO) + } + return nil +}