From df81dca720aa813b2d9617b8c87201a9dd8e7757 Mon Sep 17 00:00:00 2001 From: Andre Hahn Pereira Date: Tue, 17 Jul 2018 19:37:58 -0300 Subject: [PATCH] Initial docs --- acceptor/tcp_acceptor.go | 1 - app.go | 2 +- docs/API.md | 98 +++++++++++++++++++++++ docs/Makefile | 21 +++++ docs/conf.py | 160 +++++++++++++++++++++++++++++++++++++ docs/features.md | 106 ++++++++++++++++++++++++ docs/index.rst | 23 ++++++ docs/make.bat | 36 +++++++++ docs/overview.md | 32 ++++++++ group.go | 18 ++--- modules/binding_storage.go | 1 - pipeline/pipeline.go | 4 +- push.go | 2 +- session/session.go | 14 ++-- 14 files changed, 497 insertions(+), 21 deletions(-) create mode 100644 docs/API.md create mode 100644 docs/Makefile create mode 100644 docs/conf.py create mode 100644 docs/features.md create mode 100644 docs/index.rst create mode 100644 docs/make.bat create mode 100644 docs/overview.md diff --git a/acceptor/tcp_acceptor.go b/acceptor/tcp_acceptor.go index 64119fc7..7b4b6e6e 100644 --- a/acceptor/tcp_acceptor.go +++ b/acceptor/tcp_acceptor.go @@ -122,5 +122,4 @@ func (a *TCPAcceptor) serve() { } a.connChan <- conn } - } diff --git a/app.go b/app.go index 613ac0cd..e95d75e5 100644 --- a/app.go +++ b/app.go @@ -149,7 +149,7 @@ func Configure( logger.Log.Errorf("failed to start statds metrics reporter, skipping %v", err) } else { logger.Log.Info("successfully configured statsd metrics reporter") - app.metricsReporters = append(app.metricsReporters, metricsReporter) + AddMetricsReporter(metricsReporter) } } } diff --git a/docs/API.md b/docs/API.md new file mode 100644 index 00000000..8e44466c --- /dev/null +++ b/docs/API.md @@ -0,0 +1,98 @@ +Pitaya API +========== + +## Handlers + +Handlers are one of the core features of Pitaya, they are the entities responsible for receiving the requests from the clients and handling them, returning the response if the method is a request handler, or nothing, if the method is a push handler. + +### Signature + +Handlers must be public methods of the struct and have a signature following: + +Arguments +* `context.Context`: the context of the request, which contains the client's session. +* `pointer or []byte`: the payload of the request (_optional_). + +Push handlers return nothing, while request handlers must return: +* `pointer or []byte`: the response payload +* `error`: an error variable + + +### Registering handlers + +Handlers must be explicitly registered by the application by calling `pitaya.Register` with a instance of the handler component. The handler's name can be defined by calling `pitaya/component`.WithName(`"handlerName"`) and the methods can be renamed by using `pitaya/component`.WithNameFunc(`func(string) string`). + +The clients can call the handler by calling `serverType.handlerName.methodName`. + + +### Routing messages + +Messages are forwarded by pitaya to the appropriate server type, and custom routers can be added to the application by calling `pitaya.AddRoute`, it expects two arguments: + +* `serverType`: the server type of the target requests to be routed +* `routingFunction`: the routing function with the signature `func(*session.Session, *route.Route, []byte, map[string]*cluster.Server) (*cluster.Server, error)`, it receives the user's session, the route being requested, the message and the map of valid servers of the given type, the key being the servers' ids + +The server will then use the routing function when routing requests to the given server type. + + +### Lifecycle Methods + +Handlers can optionally implement the following lifecycle methods: + +* `Init()` - Called by Pitaya when initializing the application +* `AfterInit()` - Called by Pitaya after initializing the application +* `BeforeShutdown()` - Called by Pitaya when shutting down components, but before calling shutdown +* `Shutdown()` - Called by Pitaya after the start of shutdown + + +### Handler example + +Below is a very barebones example of a handler definition, for a complete working example, check the [cluster demo](https://github.com/topfreegames/pitaya/tree/master/examples/demo/cluster). + +```go +import ( + "github.com/topfreegames/pitaya" + "github.com/topfreegames/pitaya/component" +) + +type Handler struct { + component.Base +} + +type UserRequestMessage struct { + Name string `json:"name"` + Content string `json:"content"` +} + +type UserResponseMessage { +} + +type UserPushMessage{ + Command string `json:"cmd"` +} + +// Init runs on service initialization (not required to be defined) +func (h *Handler) Init() {} + +// AfterInit runs after initialization (not required to be defined) +func (h *Handler) AfterInit() {} + +// TestRequest can be called by the client by calling .testhandler.testrequest +func (h *Handler) TestRequest(ctx context.Context, msg *UserRequestMessage) (*UserResponseMessage, error) { + return &UserResponseMessage{}, nil +} + +func (h *Handler) TestPush(ctx context.Context, msg *UserPushMessage) { +} + +func main() { + pitaya.Register( + &Handler{}, // struct to register as handler + component.WithName("testhandler"), // name of the handler, used by the clients + component.WithNameFunc(strings.ToLower), // naming conversion scheme to be used by the clients + ) + + ... +} + +``` diff --git a/docs/Makefile b/docs/Makefile new file mode 100644 index 00000000..c3f9587a --- /dev/null +++ b/docs/Makefile @@ -0,0 +1,21 @@ +# Minimal makefile for Sphinx documentation +# + +# You can set these variables from the command line. +SPHINXOPTS = +SPHINXBUILD = sphinx-build +SPHINXPROJ = Pitaya +SOURCEDIR = . +BUILDDIR = _build + +# Put it first so that "make" without argument is like "make help". +help: + @$(SPHINXBUILD) -M help "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O) + +.PHONY: help Makefile + +# Catch-all target: route all unknown targets to Sphinx using the new +# "make mode" option. $(O) is meant as a shortcut for $(SPHINXOPTS). +%: Makefile + @$(SPHINXBUILD) -M $@ "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O) + diff --git a/docs/conf.py b/docs/conf.py new file mode 100644 index 00000000..bdeafd03 --- /dev/null +++ b/docs/conf.py @@ -0,0 +1,160 @@ +# -*- coding: utf-8 -*- +# +# Configuration file for the Sphinx documentation builder. +# +# This file does only contain a selection of the most common options. For a +# full list see the documentation: +# http://www.sphinx-doc.org/en/master/config + +# -- Path setup -------------------------------------------------------------- + +# If extensions (or modules to document with autodoc) are in another directory, +# add these directories to sys.path here. If the directory is relative to the +# documentation root, use os.path.abspath to make it absolute, like shown here. +# +# import os +# import sys +# sys.path.insert(0, os.path.abspath('.')) + +from recommonmark.parser import CommonMarkParser + +source_parsers = { + '.md': CommonMarkParser, +} + +# -- Project information ----------------------------------------------------- + +project = u'Pitaya' +copyright = u'2018, TFGCo' +author = u'TFGCo' + +# The short X.Y version +version = u'' +# The full version, including alpha/beta/rc tags +release = u'' + + +# -- General configuration --------------------------------------------------- + +# If your documentation needs a minimal Sphinx version, state it here. +# +# needs_sphinx = '1.0' + +# Add any Sphinx extension module names here, as strings. They can be +# extensions coming with Sphinx (named 'sphinx.ext.*') or your custom +# ones. +extensions = [ +] + +# Add any paths that contain templates here, relative to this directory. +templates_path = ['_templates'] + +# The suffix(es) of source filenames. +# You can specify multiple suffix as a list of string: +# +source_suffix = ['.rst', '.md'] +# source_suffix = '.rst' + +# The master toctree document. +master_doc = 'index' + +# The language for content autogenerated by Sphinx. Refer to documentation +# for a list of supported languages. +# +# This is also used if you do content translation via gettext catalogs. +# Usually you set "language" from the command line for these cases. +language = None + +# List of patterns, relative to source directory, that match files and +# directories to ignore when looking for source files. +# This pattern also affects html_static_path and html_extra_path . +exclude_patterns = [u'_build', 'Thumbs.db', '.DS_Store'] + +# The name of the Pygments (syntax highlighting) style to use. +pygments_style = 'sphinx' + + +# -- Options for HTML output ------------------------------------------------- + +# The theme to use for HTML and HTML Help pages. See the documentation for +# a list of builtin themes. +# +html_theme = 'sphinx_rtd_theme' + +# Theme options are theme-specific and customize the look and feel of a theme +# further. For a list of options available for each theme, see the +# documentation. +# +# html_theme_options = {} + +# Add any paths that contain custom static files (such as style sheets) here, +# relative to this directory. They are copied after the builtin static files, +# so a file named "default.css" will overwrite the builtin "default.css". +html_static_path = ['_static'] + +# Custom sidebar templates, must be a dictionary that maps document names +# to template names. +# +# The default sidebars (for documents that don't match any pattern) are +# defined by theme itself. Builtin themes are using these templates by +# default: ``['localtoc.html', 'relations.html', 'sourcelink.html', +# 'searchbox.html']``. +# +# html_sidebars = {} + + +# -- Options for HTMLHelp output --------------------------------------------- + +# Output file base name for HTML help builder. +htmlhelp_basename = 'Pitayadoc' + + +# -- Options for LaTeX output ------------------------------------------------ + +latex_elements = { + # The paper size ('letterpaper' or 'a4paper'). + # + # 'papersize': 'letterpaper', + + # The font size ('10pt', '11pt' or '12pt'). + # + # 'pointsize': '10pt', + + # Additional stuff for the LaTeX preamble. + # + # 'preamble': '', + + # Latex figure (float) alignment + # + # 'figure_align': 'htbp', +} + +# Grouping the document tree into LaTeX files. List of tuples +# (source start file, target name, title, +# author, documentclass [howto, manual, or own class]). +latex_documents = [ + (master_doc, 'Pitaya.tex', u'Pitaya Documentation', + u'TFGCo', 'manual'), +] + + +# -- Options for manual page output ------------------------------------------ + +# One entry per manual page. List of tuples +# (source start file, name, description, authors, manual section). +man_pages = [ + (master_doc, 'pitaya', u'Pitaya Documentation', + [author], 1) +] + + +# -- Options for Texinfo output ---------------------------------------------- + +# Grouping the document tree into Texinfo files. List of tuples +# (source start file, target name, title, author, +# dir menu entry, description, category) +texinfo_documents = [ + (master_doc, 'Pitaya', u'Pitaya Documentation', + author, 'Pitaya', 'One line description of project.', + 'Miscellaneous'), +] diff --git a/docs/features.md b/docs/features.md new file mode 100644 index 00000000..426795ad --- /dev/null +++ b/docs/features.md @@ -0,0 +1,106 @@ +Features +======== + +Pitaya has a modular and configurable architecture which helps to hide the complexity of scaling the application and managing clients' sessions and communications. + +Some of its core features are described below. + +## Standalone mode + +Pitaya has two types of operation: standalone and cluster mode. + +In standalone mode the servers don't interact with one another, don't use service discovery and don't have support to RPCs. This is a limited version of the framework which can be used when the application doesn't need to have different types of servers or communicate among them. + +## Cluster mode + +Cluster mode is a more complete mode, using service discovery, RPC client and server and remote communication among servers of the application. This mode is useful for more complex applications, which might benefit from splitting the responsabilities among different specialized types of servers. This mode already comes with default services for RPC calls and service discovery. + +### Frontend and backend servers + +In cluster mode servers can either be a frontend or backend server. + +Frontend servers must specify listeners and receive incoming client connections. They forward received messages to the appropriate servers according to the routing logic. + +Backend servers don't listen for connections, they only receive RPCs, either forwarded client messages or RPCs from other servers. + +### Listeners + +Frontend servers must specify one or more acceptors to handle incoming client connections, Pitaya comes with TCP and Websocket acceptors already implemented, and other acceptors can be added to the application by implementing the acceptor interface. + +### Message forwarding + +When a server instance receives a client message, it checks the target server type by looking at the route. If the target server type is different from the receiving server type, the instance forwards the message to an appropriate server instance of the correct type. The client doesn't need to take any action to forward the message, this process is done automatically by Pitaya. + +By default the routing function chooses one instance of the target server type at random. Custom functions can be defined to change this behavior. + +### Sessions + +Every connection established by the clients has an associated session instance, which is ephemeral and destroyed when the connection closes. Sessions are part of the core functionality of Pitaya, because they allow asynchronous communication with the clients and storage of data between requests. The main features of sessions are: + +* **ID binding** - Sessions can be bound to an user ID, allowing other parts of the application to send messages to the user without needing to know which server or connection the user is connected to +* **Data storage** - Sessions can be used for data storage, storing and retrieving data between requests +* **Message passing** - Messages can be sent to connected users through their sessions, without needing to have knowledge about the underlying connection protocol +* **Accessible on requests** - Sessions are accessible on handler requests in the context instance +* **Kick** - Users can be kicked from the server through the session's `Kick` method + +Even though sessions are accessible on handler requests both on frontend and backend servers, their behavior is a bit different if they are a frontend or backend session. This is mostly due to the fact that the session actually lives in the frontend servers, and just a representation of its state is sent to the backend server. + +A session is considered a frontend session if it is being accessed from a frontend server, and a backend session is accessed from a backend server. Each kind of session is better described below. + +#### Frontend sessions + +Sessions are associated to a connection in the frontend server, and can be retrieved by session ID or bound user ID in the server the connection was established, but cannot be retrieved from a different server. + +Callbacks can be added to some session lifecycle changes, such as closing and binding. The callbacks can be on a per-session basis (with `s.OnClose`) or for every session (with `OnSessionClose`, `OnSessionBind` and `OnAfterSessionBind`). + +#### Backend sessions + +Backend sessions have access to the sessions through the handler's methods, but they have some limitations and special characteristics. Changes to session variables must be pushed to the frontend server by calling `s.PushToFront` (this is not needed for `s.Bind` operations), setting callbacks to session lifecycle operations is also not allowed. One can also not retrieve a session by user ID from a backend server. + +### Service discovery + +Servers operating in cluster mode must have a service discovery client to be able to work. Pitaya comes with a default client using etcd, which is used if no other client is defined. The service discovery client is responsible for registering the server and keeping the list of valid servers updated, as well as providing information about requested servers as needed. + +### RPCs + +Pitaya has support for RPC calls when in cluster mode, there are two components to enable this, RPC client and RPC server. There are currently two options for using RPCs implemented for Pitaya, NATS and gRPC, the default is NATS. + +There are two types of RPCs, _Sys_ and _User_. + +#### Sys RPCs + +These are the RPCs done by the servers when forwarding handler messages to the appropriate server type. + +#### User RPCs + +User RPCs are done when the application actively calls a remote method in another server. The call can specify the ID of the target server or let Pitaya choose one according to the routing logic. + +### Groups + +Groups are structures which store information about target users and allows sending broadcast messages to all users in the group and also multicast messages to a subset of the users according to some criteria. + +### Pipelines + +Pipelines are middlewares which allow methods to be executed before and after handler requests, they receive the request's context and request data and return the request data, which is passed to the next method in the pipeline. + +### Push + +Messages can be pushed to users without previous information about either session or connection status. These push messages have a route (so that the client can identify the source and treat properly), the message, the target ids and the server type the client is expected to be connected to. + +### Modules + +Modules are entities that can be registered to the Pitaya application and must implement the defined [interface](https://github.com/topfreegames/pitaya/tree/master/interfaces/interfaces.go#L24). Pitaya is responsible for calling the appropriate lifecycle methods as needed, the registered modules can be retrieved by name. + +Pitaya comes with a few already implemented modules, and more modules can be implemented as needed. The modules Pitaya has currently are: + +#### Binary + +This module starts a binary as a child process and pipes its stdout and stderr to info and error log messages, respectively. + +#### Unique session + +This module adds a callback for `OnSessionBind` that checks if the id being bound has already been bound in one of the other frontend servers. + +#### Binding storage + +This module implements functionality needed by the gRPC RPC implementation to enable the functionality of broadcasting session binds and pushes to users without knowledge of the servers the users are connected to. diff --git a/docs/index.rst b/docs/index.rst new file mode 100644 index 00000000..a6266bd9 --- /dev/null +++ b/docs/index.rst @@ -0,0 +1,23 @@ +.. Pitaya documentation master file, created by + sphinx-quickstart on Mon Jul 16 17:01:02 2018. + You can adapt this file completely to your liking, but it should at least + contain the root `toctree` directive. + +Welcome to Pitaya's documentation! +================================== + +.. toctree:: + :maxdepth: 2 + :caption: Contents: + + overview + features + API + + +Indices and tables +================== + +* :ref:`genindex` +* :ref:`modindex` +* :ref:`search` diff --git a/docs/make.bat b/docs/make.bat new file mode 100644 index 00000000..9a66afd4 --- /dev/null +++ b/docs/make.bat @@ -0,0 +1,36 @@ +@ECHO OFF + +pushd %~dp0 + +REM Command file for Sphinx documentation + +if "%SPHINXBUILD%" == "" ( + set SPHINXBUILD=sphinx-build +) +set SOURCEDIR=. +set BUILDDIR=_build +set SPHINXPROJ=Pitaya + +if "%1" == "" goto help + +%SPHINXBUILD% >NUL 2>NUL +if errorlevel 9009 ( + echo. + echo.The 'sphinx-build' command was not found. Make sure you have Sphinx + echo.installed, then set the SPHINXBUILD environment variable to point + echo.to the full path of the 'sphinx-build' executable. Alternatively you + echo.may add the Sphinx directory to PATH. + echo. + echo.If you don't have Sphinx installed, grab it from + echo.http://sphinx-doc.org/ + exit /b 1 +) + +%SPHINXBUILD% -M %1 %SOURCEDIR% %BUILDDIR% %SPHINXOPTS% +goto end + +:help +%SPHINXBUILD% -M help %SOURCEDIR% %BUILDDIR% %SPHINXOPTS% + +:end +popd diff --git a/docs/overview.md b/docs/overview.md new file mode 100644 index 00000000..2378b6b7 --- /dev/null +++ b/docs/overview.md @@ -0,0 +1,32 @@ +Overview +======== + +Pitaya is an easy to use, fast and lightweight game server framework inspired by [starx](https://github.com/lonnng/starx) and [pomelo](https://github.com/NetEase/pomelo) and built on top of [nano](https://github.com/lonnng/nano)'s networking library. + +The goal of pitaya is to provide a basic development framework for distributed multiplayer games and server-side applications. + +## Features + +* **User sessions** - Pitaya has support for user sessions, allowing binding sessions to user ids, setting custom data and retrieving it in other places while the session is active +* **Cluster support** - Pitaya comes with support to default service discovery and RPC modules, allowing communication between different types of servers with ease +* **WS and TCP listeners** - Pitaya has support for TCP and Websocket acceptors, which are abstracted from the application receiving the requests +* **Handlers and remotes** - Pitaya allows the application to specify its handlers, which receive and process client messages, and its remotes, which receive and process RPC server messages. They can both specify custom init, afterinit and shutdown methods +* **Message forwarding** - When a server receives a handler message it forwards the message to the server of the correct type +* **Client library** - [libpitaya](https://github.com/topfreegames/libpitaya) is the official client library for Pitaya +* **Monitoring** - Pitaya has support for Prometheus and statsd support by default and accepts other custom reporters that implement the Reporter interface +* **Open tracing compatible** - Pitaya is compatible with [open tracing](http://opentracing.io/), so using [Jaeger](https://github.com/jaegertracing/jaeger) or any other compatible tracing framework is simple +* **Custom modules** - Pitaya already has some default modules and supports custom modules as well +* **Custom serializers** - Pitaya natively supports JSON and Protobuf messages and it is possible to add other custom serializers as needed + + +## Architecture + +Pitaya was developed considering modularity and extendability at its core, while providing solid basic functionalities to abstract client interactions to well defined interfaces. The full API documentation is available in Godoc format at [godoc](https://godoc.org/github.com/topfreegames/pitaya). + +## Who's Using it + +Well, right now, only us at TFG Co, are using it, but it would be great to get a community around the project. Hope to hear from you guys soon! + +## How To Contribute? + +Just the usual: Fork, Hack, Pull Request. Rinse and Repeat. Also don't forget to include tests and docs (we are very fond of both). diff --git a/group.go b/group.go index 53fb3944..ac335ded 100644 --- a/group.go +++ b/group.go @@ -35,12 +35,12 @@ const ( groupStatusClosed = 1 ) -// SessionFilter represents a filter which was used to filter session when Multicast, -// the session will receive the message while filter returns true. +// SessionFilter represents a filter which is used to filter sessions when Multicast, +// the session will receive the message when the filter returns true. type SessionFilter func(*session.Session) bool -// Group represents a session group which used to manage a number of -// sessions, data send to the group will send to all session in it. +// Group represents a session group which is used to manage a number of +// sessions, data sent to the group will be sent to all sessions in it. type Group struct { mu sync.RWMutex status int32 // channel current status @@ -110,7 +110,7 @@ func (c *Group) Multicast(route string, v interface{}, filter SessionFilter) err return nil } -// Broadcast push the message(s) to all members +// Broadcast pushes the message to all members func (c *Group) Broadcast(route string, v interface{}) error { if c.isClosed() { return constants.ErrClosedGroup @@ -141,7 +141,7 @@ func (c *Group) Contains(uid string) bool { return err == nil } -// Add add session to group +// Add adds session to group func (c *Group) Add(session *session.Session) error { if session.UID() == "" { return constants.ErrNoUIDBind @@ -165,7 +165,7 @@ func (c *Group) Add(session *session.Session) error { return nil } -// Leave remove specified UID related session from group +// Leave removes specified UID related session from group func (c *Group) Leave(s *session.Session) error { if c.isClosed() { return constants.ErrClosedGroup @@ -180,7 +180,7 @@ func (c *Group) Leave(s *session.Session) error { return nil } -// LeaveAll clear all sessions in the group +// LeaveAll clears all sessions in the group func (c *Group) LeaveAll() error { if c.isClosed() { return constants.ErrClosedGroup @@ -216,7 +216,7 @@ func (c *Group) Close() error { atomic.StoreInt32(&c.status, groupStatusClosed) - // release all reference + // release all references c.sessions = make(map[string]*session.Session) return nil } diff --git a/modules/binding_storage.go b/modules/binding_storage.go index 57fbabab..2c3d05da 100644 --- a/modules/binding_storage.go +++ b/modules/binding_storage.go @@ -156,7 +156,6 @@ func (b *ETCDBindingStorage) bootstrapLease() error { <-c go b.watchLeaseChan(c) return nil - } // Init starts the binding storage module diff --git a/pipeline/pipeline.go b/pipeline/pipeline.go index aa185225..52090654 100644 --- a/pipeline/pipeline.go +++ b/pipeline/pipeline.go @@ -39,7 +39,7 @@ type ( } ) -// PushFront should not be used after pitaya running +// PushFront should not be used after pitaya is running func (p *pipelineChannel) PushFront(h Handler) { Handlers := make([]Handler, len(p.Handlers)+1) Handlers[0] = h @@ -47,7 +47,7 @@ func (p *pipelineChannel) PushFront(h Handler) { p.Handlers = Handlers } -// PushBack should not be used after pitaya running +// PushBack should not be used after pitaya is running func (p *pipelineChannel) PushBack(h Handler) { p.Handlers = append(p.Handlers, h) } diff --git a/push.go b/push.go index d1cc0093..923c47ca 100644 --- a/push.go +++ b/push.go @@ -29,7 +29,7 @@ import ( "github.com/topfreegames/pitaya/util" ) -// SendPushToUsers sends a message to given list of users +// SendPushToUsers sends a message to the given list of users func SendPushToUsers(route string, v interface{}, uids []string, frontendType string) error { data, err := util.SerializeOrRaw(app.serializer, v) if err != nil { diff --git a/session/session.go b/session/session.go index de964bf5..968f6745 100644 --- a/session/session.go +++ b/session/session.go @@ -74,10 +74,10 @@ type HandshakeData struct { User map[string]interface{} `json:"user,omitempty"` } -// Session represents a client session which could storage temp data during low-level -// keep connected, all data will be released when the low-level connection was broken. -// Session instance related to the client will be passed to Handler method as the first -// parameter. +// Session represents a client session, which can store data during the connection. +// All data is released when the low-level connection is broken. +// Session instance related to the client will be passed to Handler method in the +// context parameter. type Session struct { sync.RWMutex // protect data id int64 // session global unique id @@ -133,6 +133,7 @@ func New(entity NetworkEntity, frontend bool, UID ...string) *Session { // GetSessionByUID return a session bound to an user id func GetSessionByUID(uid string) *Session { + // TODO: Block this operation in backend servers if val, ok := sessionsByUID.Load(uid); ok { return val.(*Session) } @@ -141,6 +142,7 @@ func GetSessionByUID(uid string) *Session { // GetSessionByID return a session bound to a frontend server id func GetSessionByID(id int64) *Session { + // TODO: Block this operation in backend servers if val, ok := sessionsByID.Load(id); ok { return val.(*Session) } @@ -161,7 +163,7 @@ func OnSessionBind(f func(ctx context.Context, s *Session) error) { sessionBindCallbacks = append(sessionBindCallbacks, f) } -// OnAfterSessionBind adds a method to be caalled when session is bound and after all sessionBind callbacks +// OnAfterSessionBind adds a method to be called when session is bound and after all sessionBind callbacks func OnAfterSessionBind(f func(ctx context.Context, s *Session) error) { // Prevents the same function to be added twice in onSessionBind sf1 := reflect.ValueOf(f) @@ -320,7 +322,7 @@ func (s *Session) OnClose(c func()) error { return nil } -// Close terminate current session, session related data will not be released, +// Close terminates current session, session related data will not be released, // all related data should be cleared explicitly in Session closed callback func (s *Session) Close() { atomic.AddInt64(&SessionCount, -1)