47. 实现iFun Deploy API¶
本部分介绍了将iFun Deploy的CS API应用到通过iFun引擎编写的服务器 上时所需的作业。
在iFun引擎中实现iFun Deploy API的部分是 DeployApiService
类。实现个别CS API时,建议使用相应类的功能。
You need the following paragraph in MANIFEST.json.
If you are using the C++ API set deploy_api_service_use_mono
to false
.
Or, if you are using the C# API, set deploy_api_service_use_mono
to true
.
1 2 3 | "DeployApiService": {
"deploy_api_service_use_mono": false
}
|
Note
Please refer to iFun Deploy documentation for details.
47.1. 须要提前知悉的事项¶
请阅读本部分内容,遵守要使用的API的相关内容。
47.1.1. 非同步发送HTTP响应¶
为了通过非同步的方式发送响应,需将指定HTTP响应的 ResponseWriter
对象
传输给API处理器。该对象会获取HTTP状态代码
(200 OK、 400 Bad request、… )及不同处理器下必要的响应值,
并作为响应进行发送。
例如,用于检验用户是否已经登录的
IsLoggedIn()
函数会获取HTTP状态代码
及与登录与否相对应的 bool
值。
struct ExampleApiHandler : public DeployApiService::DeployApiHandlerBase {
virtual void IsLoggedIn(
const string &id, const Ptr<BoolResponseWriter> &writer) const override {
AccountManager::LocateAsync(id,
[writer](const string &id, const Rpc::PeerId &node) {
// If the user is logged-in, node would not be null.
bool logged_in = !node.is_nil();
// Send HTTP response. (200 OK, bool value for login state)
writer->Write(http::kOk, &logged_in);
});
}
};
internal class ExampleDeployHandler : UserAPI {
// Implements IsUserLoggedIn, which is part of the UserAPI interface.
public void IsUserLoggedIn(string id, BoolResponseWriter writer)
{
// After locating the client using asynchronus API, sends the HTTP response.
AccountManager.LocateCallback cb = delegate (string uid, System.Guid peer_id) {
// If peer_id is not "00000000-...", the user is logged-in.
writer(StatusCode.kOk, peer_id != Guid.Empty);
};
AccountManager.LocateAsync(id, cb);
}
}
除此以外,仅需要HTTP状态代码时使用的 VoidResponseWriter
、JSON响应、
JSON的向量(vector)、string、string的向量等作为响应参数接收的各个
HTTP响应对象,将相应地传输给各个处理器。
47.1.2. 使用DeployApiHandlerBase (C++)¶
大部分API都通过将继承了 DeployApiService::DeployApiHandlerBase
类的
实现类对象注册到 DeployApiService
中的方式来实现。
将已Override的API方法显示在iFun Deploy端,其他的函数
则保持未实现的状态。
Note
由于DeployApiHandlerBase运用了C++的reflexion功能 ,所以在上级类中定义的成员函数则无法被识别。请通过一个阶段对继承了DeployApiHandlerBase 的layer加以限制。
为了明确是否已接受继承并进行override,使用上述示例中的 override
关键词
,就会十分便利。(需要设置支持C++11及其以上版本的编译器。)
47.1.3. Implementing the interfaces in DeployService (C#)¶
You may find the various interface classes in funapi.Deploy namespace.
You may implement some (or all) fo the interfaces, and then pass the implementation
class to DeployApiService.RegisterDeployApiHandler()
to process the requests from iFunDeploy.
47.2. 实现账户相关API¶
使用上面第1、2项方法。
例如,实现返回用户搜索条件的API GET /cs-api/v1/account/search-condition/
。
通过覆盖(override) DeployApiService::DeployApiHandlerBase::GetUserSearchConditions
来实现。
例如,如果允许通过用户名(nickname)和Facebook ID搜索,
则按下所示代码实现。即,通过字符串的向量格式来指定可能的条件。
class FooHandler : public DeployApiService::DeployApiHandlerBase {
virtual http::StatusCode GetUserSearchConditions(
const Ptr<StringVectorResponseWriter> &writer) const override {
std::vector<std::string> conditions;
conditions.push_back("nickname");
conditions.push_back("facebook-id");
writer->Write(fun::http::kOk, &conditions);
}
internal class ExampleDeployHandler : UserAPI {
public void GetUserSearchConditions(WriteStringListResponse writer)
{
List<String> conditions = new List<String>();
conditions.Add("nickname");
conditions.Add("facebook-id");
writer(StatusCode.kOk, conditions);
}
}
类似地,搜索用户的 GET /cs-api/v1/account/search
则通过覆盖(override) DeployApiHandlerBase::SearchUsers
来实现。
按条件搜索好用户后,将各个用户看成一个dict,添加到名为 users
的JSON array中。该API是支持打包的,
所以须要通过函数参数传输过来的 PageInfo
结构体的值来限制范围。
如果HTTP status code没有OK (fun::http::kOk
),我们假设在处理过程中发生错误,并将相关数值传输到iFun Deploy端。
For C#, you may implement the funapi.Deploy.UserAPI.SearchUsers()
.
API分别对应 DeployApiHandlerBase
中的以下各成员函数。
-
GET
/cs-api/v1/account/
(id)/
¶ GetUser(id)
. 需要实现把与 id 对应的用户数据设置 到 result 中。
-
PUT
/cs-api/v1/account/
(id)/
(field)/
(value)/
¶ UpdateUser(id, field, value)
.需要实现找到 id 对应的用户 并将 field 的值变更为 value 。如果 field 没有被指定为可变值,该函数将不被调用。 成功/失败与否可以使用HTTP status code传输至响应函数。
-
GET
/cs-api/v1/account/
(id)/connection/
¶ IsLoggedIn(id)
.传输 id 对应的用户是否已经登录 即可。 For C#, you may find theDeploy.UserAPI.IsUserLoggedIn(id)
.
-
POST
/cs-api/v1/account/
(id)/logout/
¶ ForceLogout(id)
. id 对应的用户被强制退出的功能需要被实现。 响应仅需要HTTP状态代码。For C#, you may find the
Deploy.ForceLogoutAPI.ForceLogout(id)
.
-
GET
/cs-api/v1/account/
(id)/ban/
¶ GetUserBanned(id)
id 与其对应的用户禁止与否的消息,则须要传输至响应函数。For C#, you may find the
Deploy.BanUserAPI.IsUserBanned(id)
.
-
POST
/cs-api/v1/account/
(id)/ban/
¶ BanUser(id)
id 与其对应的用户,则须要被禁止。 响应仅需要HTTP状态代码。For C#, you may find the
Deploy.BanUserAPI.BanUser(id)
.
-
POST
/cs-api/v1/account/
(id)/reinstate/
¶ UnbanUser(id)
id 与其对应的用户,则须要被解禁。 响应仅需要HTTP状态代码。For C#, you may find the
Deploy.BanUserAPI.UnbanUser(id)
.
同时,可在 UpdateUser
中变更的项目可通过
调用 DeployApiService::SetEditableFieldsForUser()
函数进行指定。
For C#, you may invoke the DeployApiService.SetEditableFieldsForUser()
method to
specify the editable fields.
47.3. 实现人物相关API¶
和账户相关API一样,使用第1、2项方法。
-
GET
/cs-api/v1/account/
(id)/character/
¶ GetCharacters(id)
. 需要实现将 id 对应的用户人物ID和画面显示的名字信息分别保存在不同的 JSON上,然后将包含该信息的vector<fun::Json>
的数据 传输至响应函数。For C#, you should implement the
UserAPI.GetCharacters()
method.
-
GET
/cs-api/v1/character/
(id)/
¶ GetCharacter(id)
. 需要实现与 id 对应的用户人物ID信息以JSON object的形式 响应。例如,将如下内容添加到响应函数中 调用即可。For C#, please implement the
CharacterAPI.GetCharacter(id)
method.{ "nickname": "foo", "level": 12 }
-
PUT
/cs-api/v1/character/
(id)/
(field)/
(value)/
¶ UpdateCharacter(id, field, value)
. 需要实现将 id 对应的用户人物 field 值变更为 value 。如果 field 没有被指定为可变值,该函数将不被调用。 成功/失败与否将通过HTTP status code通知。For C#, please implement the
CharacterAPI.UpdateCharacter(id, field, value)
.
须将想要在 UpdateCharacter
中变更的字段指定为
DeployApiService::SetEditableFieldsForCharacter()
。
For C#, it is handled by DeployApiService.SetEditableFieldsForCharacter()
.
47.4. 实现背包相关API¶
-
GET
/cs-api/v1/character/
(id)/inventory/
¶ GetCharacterInventoryInfo(id)
. id 与其对应的角色背包为何种类型,须要将此传输至 响应函数才行。 例如,假设存在 weapon 型的背包插槽 left_hand , right_hand 和 armor 型的背包插槽 head , body ,则按如下所示进行指定 即可。using InventoryInfoResponseWriter = ResponseWriterT< DeployApiService::DeployApiHandlerBase::InventoryInfo>; virtual http::StatusCode GetCharacterInventoryInfo( const std::string &charcter_id, const Ptr<InventoryInfoResponseWriter> &writer) const override { DeployApiService::DeployApiHandlerBase::InventoryInfo result; result.emplace_back( make_pair<string, vector<string>>("weapon", {"left_hand", "right_hand"})); result.emplace_back( make_pair<string, vector<string>>("armor", {"head", "body"})); writer->Write(http::kOk, &result); }
// InventoryAPI.GetCharacterInventoryInfo public void GetCharacterInventoryInfo( string char_id, InventoryInfoResponseWriter writer) { var inventory_list = new List<Tuple<string, List<string>>>(); var weapon = new Tuple<string, List<String>>("weapon", new List<string>()); weapon.Item2.Add("left_hand"); weapon.Item2.Add("right_hand"); inventory_list.Add(weapon); var armor = new Tuple<string, List<String>>("armor", new List<string>()); armor.Item2.Add("head"); armor.Item2.Add("body"); inventory_list.Add(armor); writer(StatusCode.kOk, inventory_list); }
-
GET
/cs-api/v1/inentory/
(type)/
(id)/
¶ GetInventory(type, id)
.需要通过JSON array 的形式在 result 中对相应背包中的道具进行设置。(在Deploy中将自动转换为 必要的格式。)该函数传输Paging相关参数,实现时须进行 Paging处理。
-
POST
/cs-api/v1/inventory/<type>/<inv_id>/item/<item_id>/
¶ DeleteInventoryItem(type, id, item_id)
需要在背包类型为 type ,ID为 id 的地方删除 item_id 对应的 道具。结果值通过HTTP status code 返回。An expected_quantity means the displays quantity of the item, and the method should decrease the item quantity by reclaimed.
This function is only used by the C++ API.
-
POST
/cs-api/v1/inventory/
¶ C++:
DeleteMultipleInventoryItems()
C#:
InventoryAPI.DeleteInventoryItem()
The handler will receive the list of items to be reclaimed by CS tool. The list is categorized by (inventory type, inventory id).
Results are returned in HTTP status code.
47.5. 实现道具发放相关API¶
可发放的道具ID通过 SetGiftableItems()
函数指定。
须要在该函数中传输由”道具ID、名称”组成的pair向量。
实现以下API,即可进行实际的发放处理。
-
POST
/cs-api/v1/item/gift/
¶ GiveGift(target_type, title, content, expires, items, users, writer)
Gifts item to accounts or characters.
The target_type would have value either
account
orcharacter
. Based on this value, one should gift items to users.A message is sent along with the item (title: title, content: content) This item is sent with expiry date as expires. items A list of items to be gifted to items is also sent and item IDs are only permitted in
SetGiftableItems()
.GiveGiftToAll(target_type, title, content, expires, items, writer)
Gift item to all accounts or to all characters. (Depends on
target_type
)If you try to gift items that have not been designated, an error log is left and this callback is not invoked.
47.6. 实现活动(Event)相关API¶
首先通过 DeployApiService::RegisterCampaignType()
函数设置可在Deploy
中指定的活动。
在相应函数中须要设置的值请参考 DeployApiService::Campaign
结构体类型
进行指定。
在iFun Deploy中设置活动后需要调用的函数请在 RegisterBeginCampaignCallback()
中指定,活动结束后调用的函数请在 RegisterEndCampaignCallback()
中指定。
47.7. 实现自定义Query¶
可通过注册 DeployApiService::RegisterCustomQueryHandler()
函数来添加
自定义Query。
static void RegisterCustomQueryHandler(
const std::string &name, // display name
const http::Method &method, // HTTP verb
const std::string &uri, // URI (MUST NOT include regex)
// JSON attributes which should be provided by JSON request body
const std::vector<std::string> &request_fields,
// JSON attributes which should be placed in JSON response
// (for successful response)
const std::vector<std::string> &response_fields,
const CustomApiHandler &handler);
public class DeployApiService {
public static void RegisterCustomApiHandler(
string name,
http.Method method,
string uri,
IEnumerable<string> request_fields,
IEnumerable<string> response_fields,
Deploy.CustomApiHandler handler);
}
这里的 name
仅仅是在画面上显示的值。
通过HTTP method
指定的 GET
、 POST
、… 及 URI
值是在实际调用
时使用的API。
可以分别指定须要在相应的自定义Query请求和响应中
包含的字段列表,如果请求中没有相应字段,将不会调用
已通过 handler
指定的函数,而仅保存错误日志。
相反,如果响应中不存在已指定的字段,响应会被传送,但同时也会留下警告日志。
自定义Query处理器也使用 非同步HTTP响应 。