6. Configuration file (MANIFEST.json)

6.1. What is MANIFEST.json?

iFun Engine features can be configured in a configuration file called MANIFEST.json. MANIFEST.json has the following structure.

Note

In the following example, Comments beginning with // are only to aid comprehension and are not included in the JSON file.

6.1.1. MANIFEST.json file structure

{
  // Shows the MANIFEST.json schema version Currently, this must always be 1.
  "version": 1,

  "components": [
    {
      // This is the name of your game server's component.
      // If a project is created as "funapi_initiator my_project", it becomes MyProjectServer.
      "name": "MyProjectServer",

      // If you need to exceed the parameters in your game server component, proceed as follows.
      // (my_component_arg1 and my_component_arg2 are names used as examples.)
      "arguments": {
        "my_component_arg1": integer_value,
        "my_component_arg2": "string_value"
      },

      // Specify the shared object file name generated for your game build.
      // If your project is created as "funapi_initiator my_project", it becomes libmy_project.so.
      "library": "libmy_project.so",

      // Set the values of your iFun Engine features here.
      // iFun Engine features are defined in /usr/share/funapi/manifests/*/MANIFEST.json.
      "dependency": {

        ...

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

        ...

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

        ...
      }
    }
  ]
}

6.2. Encrypting Data in MANIFEST.json

You may need to save sensitive information such as your DB password in MANIFEST.json. This is not usually a serious problem since only developers with source access permission during the development process and administrators accessing the live server in a service environment can view MANIFEST.json. However, you can encrypt sensitive information within MANIFEST.json to keep it safer.

You can only encrypt MANIFEST.json text strings, and since encryption is based on a license file, you need to run the following funapi_argument_encryptor in a development environment with the account.ilf you will use on your game server installed.

6.2.1. Encrypting text strings

Enter the following to encrypt a text string called mypassword.

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

If the installed account.ilf differs from that installed on the game server, specify the license file path as follows and encrypt:

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

6.2.2. Using encrypted text strings in MANIFEST.json

Enter the value for the Encrypted argument generated above into the MANIFEST file. For example, if db_mysql_pw is mypassword, it is encrypted as follows:

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

6.3. Temporarily overriding MANIFEST.json

MANIFEST.json is distributed along with the game server program to the machine used for the live service and contains static data shared by all the machines. Therefore, it is not advisable to manually modify MANIFEST.json installed on a service host. This method is prone to creating errors when there are a large number of servers.

However, in very special cases, you may have no choice but to modify MANIFEST.json for service hosts to suit each machine. In such cases, you can override the data in MANIFEST.json with a separate file.

Important

This file is configured temporarily for each host, and therefore is not included when packaging game service.

If, for example, you have created a project like funapi_initiator my_project and packaged the project, you will get a file on the service host with the name /etc/my_project/MANIFEST.override.json when unpacking the package.

If you are using Flavors: Identifying servers according to their role and override the configuration only for my_flavor, you need to create a file named /etc/my_project/MANIFEST.my_flavor.override.json.

For example, if you have defined a flavor called game in a project called hello, it will be /etc/hello/MANIFEST.game.override.json.

Write the information in the following format:

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

A JSON property named override must first exist with a list of iFun Engine function names and the saved values needed for each function. In the example above, the ApiService‘s api_service_port, and SessionService‘s tcp_json_port and udp_json_port are overriden.

6.4. MANIFEST.json example (for funapi_initiator my_project)

The example below is the MANIFEST.json automatically generated for the above my_project. By looking at dependency you can see how the values for the iFun Engine functions used in my_project have changed. Please refer to Configuration file (MANIFEST.json) details for each function and the parameters that can be configured.

{
  "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"
    }
  ]
}