7. 配置文件(MANIFEST.json)

7.1. 什么是MANIFEST.json?

iFun引擎的功能可通过名为 MANIFEST.json 的配置文件来设置。 MANIFEST.json 的结构如下。

Note

在以下示例中以//开头的注释仅用于帮助理解,而不包含在JSON file中。

7.1.1. MANIFEST.json 的结构

{
  // 表示MANIFEST.json schema版本。目前须保持为1。
  "version": 1,

  "components": [
    {
      // 我的游戏服务器的Component名。
      // 通过"funapi_initiator my_project"创建项目后,变为MyProjectServer。
      "name": "MyProjectServer",

      // 若需要向游戏服务器组件传送参数,请按如下方法使用。
      // (my_component_arg1和my_component_arg2是作为示例使用的名称。)
      "arguments": {
        "my_component_arg1": integer_value,
        "my_component_arg2": "string_value"
      },

      // 叙述游戏构建生成的shared object文件名。
      // 通过"funapi_initiator my_project"创建项目后,变为libmy_project.so。
      "library": "libmy_project.so",

      // 在此处指定已使用的iFun引擎各个功能的设置值。
      // iFun引擎功能已在/usr/share/funapi/manifests/*/MANIFEST.json中定义。
      "dependency": {

        ...

        "SessionService": {
          "tcp_json_port": 8012,
          ...
        },

        ...

        "IoService": {
          "internal_threads_size": 2,
          ...
        }

        ...
      }
    }
  ]
}

7.2. MANIFEST.json 内容加密

有时须在MANIFEST.json中通过DB加密等方式来保存敏感信息。在开发过程中,只有具有代码访问权限的开发人员才能够访问,在服务环境中,只有可以访问live server的管理员才能够查看MANIFEST.json,所以大部分情况下不会造成什么问题,但为了更加安全地管理,可以对MANIFEST.json内的敏感信息进行加密。

MANIFEST.json加密仅支持字符串值,基于许可证文件来运行,因此须要在游戏服务器中使用的 account.ilf 已被设置的开发环境中执行以下 funapi_argument_encryptor

7.2.1. 字符串加密

输入以下代码,为 mypassword 字符串加密。

$ funapi_argument_encryptor "mypassword"
/etc/ifunfactory/account.ilf loaded.
Argument: mypassword
Encrypted argument: __ENCA_[ASnbrseCc050UsCHZWzV5A]

若已安装的 account.ilf 不同于已安装在游戏服务器中的内容,可以按如下方法,明确指定许可证文件路径,并进行加密。

$ funapi_argument_encryptor "mypassword" /path/to/game/servers/account.ilf
/path/to/game/servers/account.ilf loaded.
Argument: mypassword
Encrypted argument: __ENCA_[ASnbrseCc050UsCHZWzV5A]

7.2.2. 将加密后的字符串应用到MANIFEST.json

将上面生成的 Encrypted argument 值直接输入到MANIFEST文件中。以下示例是当 db_mysql_pwmypassword 时,对其进行加密并指定的情况。

...
"Object": {
    ...,
    "db_mysql_server_address" : "tcp://127.0.0.1:3306",
    "db_mysql_id" : "funapi",
    "db_mysql_pw" : "__ENCA_[ASnbrseCc050UsCHZWzV5A]",
    "db_mysql_database" : "funapi",
    ...
},
...

7.3. 临时重写MANIFEST.json

MANIFEST.json在将游戏服务器程序被发布到实际提供服务的设备上时一同发布,它拥有在所有设备上共同应用的静态信息。因此,最好不要在提供服务的主机上对已发布并安装的MANIFEST.json进行手动修改。因为这样会随着服务器数量的增多而引发管理问题。

然而,在非常特殊的情况下,也有必须在提供服务的主机上按照 各个设备 对MANIFEST.json进行修改的情况。此时,可以设置一个对MANIFEST.json的内容进行override的单独文件。

Important

该文件相当于对各个主机的临时设置,因此在 对游戏服务打包时 不包含在内。

若已经以 funapi_initiator my_project 的名字创建了项目,则在服务主机上以 /etc/my_project/MANIFEST.override.json 的名字来创建文件。

若仅在使用 Flavor: 按不同作用来区分服务器 功能的my_flavor的情况下进行override设置,则以 /etc/my_project/MANIFEST.my_flavor.override.json 的名字来创建文件。

例如,在名为 hello 的项目中,若已定义了名为 game 的flavor,就会变为 /etc/hello/MANIFEST.game.override.json

然后,按以下形式编写代码。

{
  "override": {
    "ApiService": {
      "api_service_port": 9014
    },
    "SessionService": {
      "tcp_json_port": 0,
      "udp_json_port": 8017
    }
  }
}

首先,须存在名为 override 的JSON属性值,其中罗列iFun引擎功能名称,指定各个功能所需的设置值。上述示例是对 ApiServiceapi_service_port, SessionServicetcp_json_port, udp_json_port 进行override的情况。

7.4. MANIFEST.json 示例 (funapi_initiator my_project 的情况)

以下示例是在上面的 my_project 时,自动生成的MANIFEST.json。通过 dependency 项可以了解怎样变更 my_project 所使用的各个iFun引擎功能的设置值。对于各个功能及可设置的参数,请参考 配置文件(MANIFEST.json)详情

{
  "version": 1,
  "components": [
    {
      "name": "MyProjectServer",
      "arguments": {
        "example_arg1": "val1",
        "example_arg2": 100
      },
      "dependency": {
          "AppInfo": {
            "app_id": "MyProject",
            "client_current_version": "0.0.3",
            "client_compatible_versions": ["0.0.1", "0.0.2"],
            "client_update_info": "",
            "client_update_uri": ""
          },
          "EventDispatcher": {
            "event_threads_size": 4,
            "enable_event_profiler": true,
            "enable_outstanding_event_profilier": true,
            "slow_event_log_threshold_in_ms": 300,
            "event_timeout_in_ms": 30000,
            "enable_inheriting_event_tag": true,
            "enable_random_event_tag": true,
            "enable_event_thread_checker": true
          },
          "Logging": {
            "activity_log_output": "json://activity/activity_log.json",
            "activity_log_rotation_interval": 60,
            "activity_log_write_schema": true,
            "glog_flush_interval": 1,
            "glog_retention_period_in_days": 30
          },
          "IoService": {
            "internal_threads_size": 4
          },
          "SessionService": {
            "tcp_json_port": 8012,
            "udp_json_port": 0,
            "http_json_port": 8018,
            "tcp_protobuf_port": 0,
            "udp_protobuf_port": 0,
            "http_protobuf_port": 0,
            "session_timeout_in_second" : 300,
            "use_session_reliability": false,
            "use_sequence_number_validation": false,
            "use_encryption": false,
            "tcp_encryptions": ["ife1", "ife2"],
            "udp_encryptions": ["ife2"],
            "http_encryptions": [],
            "encryption_ecdh_key": "02d87cf9965f27cec9dd399b00cde2fb1c39af4711df5a1cb96a79f597c2e1b8",
            "disable_tcp_nagle": true,
            "enable_http_message_list": true,
            "session_message_logging_level": 0,
            "enable_per_message_metering_in_counter": false,
            "json_protocol_schema_dir": "json_protocols",
            "ping_sampling_interval_in_second": 0,
            "ping_message_size_in_byte": 0,
            "ping_timeout_in_second": 0,
            "close_transport_when_session_close": true,
            "send_session_id_as_string": true
          },
          "Timer": {},
          "Object": {
            "enable_database" : false,
            "cache_expiration_in_ms": 300000,
            "copy_cache_expiration_in_ms": 700,
            "enable_delayed_db_update" : false,
            "db_update_delay_in_second" : 10,
            "db_mysql_server_address" : "tcp://127.0.0.1:3306",
            "db_mysql_id" : "funapi",
            "db_mysql_pw" : "funapi",
            "db_mysql_database" : "funapi",
            "db_read_connection_count" : 8,
            "db_write_connection_count" : 16,
            "db_key_shard_read_connection_count" : 8,
            "db_key_shard_write_connection_count" : 16,
            "db_character_set": "utf8",
            "use_db_select_transaction_isolation_level_read_uncommitted": true,
            "use_db_stored_procedure": true,
            "export_db_schema": false,
            "use_db_char_type_for_object_id": false,
            "enable_assert_no_rollback" : true
          },
          "AccountManager": {
            // To redirect client to servers behind load-balancers, set
            // redirection_strict_check_server_id to "false".
            "redirection_strict_check_server_id": true,
            // Secret hexdecimal string used to protect redirection-procedure
            // from tampering.
            "redirection_secret": "403f217b685f437df905541b5e3286f1725153f7a95e63d1c0158731d52c0d5f"
          },
          "CounterService": {
            "counter_flush_interval_in_sec": 0,
            "counter_monitoring_interval_in_sec": 30,
            "warning_threshold_event_queue_length": 3000,
            "warning_threshold_outstanding_fetch_query": 5000,
            "warning_threshold_outstanding_update_query": 5000
          },
          "RuntimeConfiguration": {
            "enable_runtime_configuration": true,
            "additional_configurations": []
          },
          "ApiService": {
            "api_service_port": 8014,
            "api_service_event_tags_size": 1,
            "api_service_logging_level": 2
          },
          "AuthenticationClient": {
            "use_authenticator" : false,
            "remote_authenticator_ip_address" : "127.0.0.1",
            "remote_authenticator_port" : 12800
          },
          "BillingClient": {
            "use_biller" : false,
            "remote_biller_ip_address" : "127.0.0.1",
            "remote_biller_port" : 12810,
            "googleplay_refresh_token" : "",
            "googleplay_client_id" : "",
            "googleplay_client_secret" : ""
          },
          "LeaderboardClient": {
            "use_leaderboard" : false,
            "leaderboard_agents": {
              "" : {
                "address": "127.0.0.1:12820",
                "fallback_servers": []
              }
            }
          },
          "ClientResourceService": {
            "use_client_resource_service" : false,
            "client_resource_service_port" : 0,
            "client_resource_dir" : "client_data",
            "client_resource_url_base": "",
            "client_resource_list_url": "",
            "client_resource_service_threads_size": 2,
            "client_resource_max_file_size": 10485760
          },
          "MapLoader": {
            "use_map_loader": false,
            "map_export_path": "",
            "map_server_url": ""
          },
          "SystemInfo": {
            "systeminfo_refresh_interval_in_sec": 5
          },
          "ResourceManager": {
            "game_json_data_dir": "game_data",
            "enable_game_data_mysql": false,
            "game_data_mysql_server": "tcp://localhost:3306",
            "game_data_mysql_username": "funapi",
            "game_data_mysql_password": "funapi",
            "game_data_mysql_database": "game_data",
            "game_data_mysql_character_set": "utf8",
            "game_data_mysql_tables": "game_data_table1,game_data_table2"
          },
          "Redis": {
            "enable_redis": false,
            "redis_mode": "redis",
            "redis_servers": {
              "": {
                "address": "127.0.0.1:6379",
                "auth_pass": ""
              }
            },
            "redis_sentinel_servers": {
              "": {
                "master_name": "mymaster",
                "addresses": ["127.0.0.1:26379"],
                "auth_pass": ""
              }
            },
            "redis_async_threads_size": 4
          },
          "MaintenanceService": {
            "under_maintenance": false,
            "maintenance_data_path": ""
          },
          "RpcService": {
            "rpc_enabled": false,
            "rpc_threads_size": 4,
            "rpc_port": 8015,
            "rpc_nic_name": "",  // if not specified, uses first NIC appeared in predictable network interface names.
            "rpc_tags": [],
            "rpc_message_logging_level": 0,
            "rpc_disable_tcp_nagle": true,
            "enable_rpc_reply_checker": true
          },
          "ZookeeperClient": {
            "zookeeper_nodes": "localhost:2181",
            "zookeeper_client_count": 4,
            "zookeeper_session_timeout_in_second": 60
          },
          "HardwareInfo": {
            "external_ip_resolvers": "aws,nic:eth0,nat:192.0.2.113:tcp+pbuf=8012:http+json=8018"
          },
          "Curl": {
            "curl_threads_size": 1
          },
          "CrossServerStorage": {
            "enable_cross_server_storage": false,
            "redis_tag_for_cross_server_storage": ""
          }
      },
      "library": "libmy_project.so"
    }
  ]
}