NotificationsEditor - Mini-IT/SnipeWiki GitHub Wiki
The editor can send notifications and requests to the cache server. This article describes the API for it. There are three groups of requests to the cache server. The first group is routed to the editor request handlers of specific modules. The second one can receive and update any blocks on the cache server if they are unlocked. The request in the third group can directly update user parameters even if the user is currently playing. All of these requests use a low-level API described in the following section.
All of the requests in this article are based on one of two low-level methods: EditServer.request()
and EditServer.notify()
. The notify()
call is also based on request()
but closes the connection immediately without waiting for a response. If you wish you can use low-level calls instead.
Usage examples:
var ret = server.request("core/profiler.get", {});
server.notify('core/profiler.update', { state: 'start' });
The main idea behind editor-specific calls is that they are routed to special handlers in modules. These modules can do some work, return data, etc. All requests except the one to receive data are also propagated to all slave servers (this behavior can be disabled). Usually they are used to notify the cache server about changes in the static data in database that needs to be reloaded.
To get data from the cache server you need to use the EditServer.get()
call. The type supplied will be used to find the appropriate cache server module and call its ModuleCache.editGet()
handler. The object it returns will be received on the editor side.
Usage example (editor side):
var item: { id: Int, amount: Int } = server.get('shop.item', { id: id });
Cache server side ("shop" module):
public override function editGet(c: SlaveClientTest, type: String, params: Params): Dynamic
{
var response: Dynamic = { errorCode: 'ok' };
if (type == 'shop.item')
{
var id = params.getInt('id');
var item = get(id);
response = {
id: id,
amount: item.amount,
};
}
return response;
}
Adding data to the cache server is done with EditServer.add()
call. On the cache server side the ModuleCache.editAdd()
handler will be called. The editor will receive the response it returns.
This notification will be propagated to all slave servers. If they have the module with such name, its Module.editChangedEvent()
will be called. By default it calls Module.loadTables()
. If the cache server handler is not used, the notification will still be propagated to slave servers.
If you do not want to propagate the notification to slave servers, set the noSlaves
field of cache server handler response to true
.
Usage example (editor side):
var ret = server.add('shop.item',
{ id: id, amount: amount });
Cache server side ("shop" module):
public override function editAdd(c: SlaveClientTest, type: String, params: Params): Dynamic
{
// var response: Dynamic = { errorCode: 'ok', noSlaves: true };
var response: Dynamic = { errorCode: 'ok' };
_acquire();
if (type == 'shop.item')
{
// logic
}
_release();
return response;
}
Note the use of _acquire()
and _release()
. Since the cache server is inherently multi-threaded, we need to acquire the lock on data before changes.
Game server side ("shop" module):
override function editChangedEvent(type: String, params: Dynamic)
{
if (type == 'item')
{
// logic
}
else loadTables();
}
Note that the "type" variable on slave server does not have module name in front.
In general, updating data is not much different from adding data. Updating data on the cache server is done with EditServer.update()
call. On the cache server side the ModuleCache.editUpdate()
handler will be called. The editor will receive the response that it returns.
This notification will be propagated to all slave servers. If they have the module with such name, its Module.editChangedEvent()
will be called. By default it calls Module.loadTables()
. If the cache server handler is not used, the notification will still be propagated to slave servers.
If you do not want to propagate the notification to slave servers, set the noSlaves
field of cache server handler response to true
.
Usage example (editor side):
var ret = server.update('shop.item',
{ id: id, amount: amount });
Cache server side ("shop" module):
public override function editUpdate(c: SlaveClientTest, type: String, params: Params): Dynamic
{
// var response: Dynamic = { errorCode: 'ok', noSlaves: true };
var response: Dynamic = { errorCode: 'ok' };
_acquire();
if (type == 'shop.item')
{
// logic
}
_release();
return response;
}
Note the use of _acquire()
and _release()
. Since the cache server is inherently multi-threaded, we need to acquire the lock on data before changes.
Game server side ("shop" module):
override function editChangedEvent(type: String, params: Dynamic)
{
if (type == 'item')
{
// logic
}
else loadTables();
}
Note that the "type" variable on slave server does not have module name in front.
Just like adding and updating, deleting data will generate the same flow. Deleting data on cache server is done with EditServer.del()
call. On the cache server side the ModuleCache.editDel()
handler will be called. The editor will receive the response it returns.
This notification will be propagated to all slave servers. If they have the module with such name, its Module.editChangedEvent()
will be called. By default it calls Module.loadTables()
. If the cache server handler is not used, the notification will still be propagated to slave servers.
If you do not want to propagate the notification to slave servers, set the noSlaves
field of cache server handler response to true
.
Usage example (editor side):
var ret = server.del('shop.item',
{ id: id, amount: amount });
Cache server side ("shop" module):
public override function editDel(c: SlaveClientTest, type: String, params: Params): Dynamic
{
// var response: Dynamic = { errorCode: 'ok', noSlaves: true };
var response: Dynamic = { errorCode: 'ok' };
_acquire();
if (type == 'shop.item')
{
// logic
}
_release();
return response;
}
Note the use of _acquire()
and _release()
. Since the cache server is inherently multi-threaded, we need to acquire the lock on data before changes.
Game server side ("shop" module):
override function editChangedEvent(type: String, params: Dynamic)
{
if (type == 'item')
{
// logic
}
else loadTables();
}
Note that the "type" variable on the slave server does not have a module name in front.
Same thing here. Reloading data on cache server is done with EditServer.reload()
call. On the cache server side the ModuleCache.editReload()
handler will be called. The editor will receive the response it returns.
This notification will be propagated to all slave servers. If they have the module with such name, its Module.editChangedEvent()
will be called. By default it calls Module.loadTables()
. If the cache server handler is not used, the notification will still be propagated to slave servers.
If you do not want to propagate the notification to slave servers, set the noSlaves
field of cache server handler response to true
.
You can also add a "reload" field to any module export, that will do the same thing after export handling.
Usage example (editor side):
var ret = server.reload('shop.item', { id: id });
Cache server side ("shop" module):
public override function editReload(c: SlaveClientTest, type: String, params: Params): Dynamic
{
// var response: Dynamic = { errorCode: 'ok', noSlaves: true };
var response: Dynamic = { errorCode: 'ok' };
_acquire();
if (type == 'shop.item')
{
// logic
}
_release();
return response;
}
Note the use of _acquire()
and _release()
. Since the cache server is inherently multi-threaded, we need to acquire the lock on data before changes. Every cache server module has these calls available to acquire and release module-wide lock.
Game server side ("shop" module):
override function editChangedEvent(type: String, params: Dynamic)
{
if (type == 'item')
{
// logic
}
else loadTables();
}
Note that the "type" variable on slave server does not have a module name in front.
There is a method to send a request to any slave server directly from the editor. It is called EditServer.requestSlave()
. It has the same arguments as the EditServer.request()
except for the host and port arguments.
Note that you should have special considerations when making such requests. Any request to the game server can be potentially done by a malicious client since the game server is open for connections from the Internet. So if you need this for testing purposes, do not forget to disable the handlers on the production game servers.
Usage example:
var ret = server.requestSlave(
server.config.get('game.host'),
server.config.getInt('game.port'),
'serverStats.get', {});
p('Stats: ' + ret.list);
There is an API to get and update generic data cache blocks on the cache server. You can only update the block if it is currently unlocked. You can get the locked block contents, but they may be out of date since the block is currently used by one of slave servers and possibly modified.
Getting block contents is done with EditServer.getBlock()
method call. Updating block contents is done with EditServer.updateBlock()
method call.
Usage example:
var block = server.getBlock('user', id);
var params = block.get('params');
var list: List<Dynamic> = params.inventory.list;
list.push({ id: itemid, amount: amount });
server.updateBlock('user', id, { params: { inventory: { list: list } } });
This example receives the user block contents, adds a new item into inventory and updates user block on cache server. Note that this usage is not recommended in case of user blocks, this is just an example. It is better to update user data with EditServer.updateUser()
.
You can update user block attributes directly with EditServer.updateUser()
method call. This method does not have the limitations of EditServer.updateBlock()
. If the user is currently logged in to one of the slave servers, the block will be updated on that server without any issues.
Usage example:
var block = server.getBlock('user', id);
var params = block.get('params');
var list: List<Dynamic> = params.inventory.list;
list.push({ id: itemid, amount: amount });
server.updateUser(id, 'inventory', 'list', list);
Like in the previous example, we get the user block contents, add an item to inventory and update user block.