6. 설정 파일 (MANIFEST.json)

6.1. MANIFEST.json 이란?

아이펀 엔진의 기능은 MANIFEST.json 이라는 설정 파일을 통해 설정할 수 있습니다. MANIFEST.json 은 다음 구조로 되어있습니다.

Note

아래 예제에서 // 로 시작하는 주석은 단순히 이해를 돕기 위한 것이고, JSON file 안에는 포함되지 않습니다.

6.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",

      // 사용된 아이펀 엔진 기능들의 설정값을 여기에 지정합니다.
      // 아이펀 엔진 기능들은 /usr/share/funapi/manifests/*/MANIFEST.json 에 정의되어 있습니다.
      "dependency": {

        ...

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

        ...

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

        ...
      }
    }
  ]
}

6.2. MANIFEST.json 내용 암호화

MANIFEST.json 에는 DB 암호 등 민감한 정보를 저장해야 될 수 있습니다. 개발 과정에서는 소스 접근 권한이 있는 개발자들만 접근하고, 서비스 환경에서는 라이브 서버에 접근할 수 있는 관리자만이 MANIFEST.json 을 볼 수 있기 때문에 대개의 경우는 큰 문제가 되지 않지만, 더 안전하게 관리하기 위해 MANIFEST.json 내의 민감한 정보를 암호화 할 수 있습니다.

MANIFEST.json 암호화는 문자열 값만 가능하며 라이센스 파일을 기반으로 작동하기 때문에 게임 서버에서 사용될 account.ilf 가 설치된 개발 환경에서 아래의 funapi_argument_encryptor 를 실행해야됩니다.

6.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]

6.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",
    ...
},
...

6.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 프로퍼티가 존재해야되며, 그 안에 아이펀 엔진 기능 이름을 나열하고, 각 기능별로 필요한 설정값을 저장합니다. 위의 예는 ApiServiceapi_service_port, SessionServicetcp_json_port, udp_json_port 를 override 한 경우입니다.

6.4. MANIFEST.json 예시 (funapi_initiator my_project 의 경우)

아래의 예는 위의 my_project 의 경우 자동 생성된 MANIFEST.json 입니다. dependency 항목을 보시면 my_project 가 사용하는 아이펀 엔진의 기능들의 설정 값을 어떻게 변경하는지 보실 수 있습니다. 각 기능과 설정 가능한 파라미터들에 대해서는 설정 파일 (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"
    }
  ]
}