Package diarkis ▷
Diarkis server SDK allows you to write your own Diarkis server.
Diarkis Server Cluster
Diarkis server is designed to work as a cluster of servers where all servers within the cluster are able to communicate with each other freely.
Each server has their server type assigned and servers with the same type are grouped together in the cluster.
Default server types are based on each server's network protocol such as HTTP, UDP, and TCP.
The diagram below shows a very simplified Diarkis server cluster structure:
╔══════════════════════════════════════════════════════════════════╗
║ kubernetes ║
║ ┌─────────────────────────────────────────┐ ║
║ │ △ Diarkis Server Cluster │ ║
║ │ │ ║
║ │ UDP Servers │ ║
║ │ ╭╌╌╌╌╌╌╌╌╌╌╌╌╌╌╮ │ ║ Server-to-Client Direct communication
║ │ ╎ ┏━━━━━━┓┓┓ ╎ │ ║ ╭────────────────╮╮╮
║ │ ╎ ┃ UDP ┃┃┃ ╎─────────────────│───║─────────────│ Client Devices │││
║ │ ╎ ┗━━━━━━┛┛┛ ╎ │ ║ ╰────────────────╯╯╯
║ │ ╰╌╌╌╌╌╌╌╌╌╌╌╌╌╌╯ │ ║
║ │ ║ │ ║
║ │ ║ Internal communication │ ║
║ │ ║ │ ║
║ │ HTTP Servers │ ║
║ │ ╭╌╌╌╌╌╌╌╌╌╌╌╌╌╌╮ │ ║
║ ┌───────────────┐ │ ╎ ┏━━━━━━┓┓┓ ╎ ┏━━━━━━┓ │ ║
║ │ Load balancer │╌╌│╌╌╌╌╌╌╌╌╎ ┃ HTTP ┃┃┃ ╎ ┃ MARS ┃ │ ║
║ └───────────────┘ │ ╎ ┗━━━━━━┛┛┛ ╎ ┗━━━━━━┛ │ ║
║ ╎ │ ╰╌╌╌╌╌╌╌╌╌╌╌╌╌╌╯ │ ║
║ ╎ │ ║ │ ║
║ ╎ │ ║ Internal communication │ ║
║ ╎ │ ║ │ ║
║ ╎ │ TCP Servers │ ║
║ ╎ │ ╭╌╌╌╌╌╌╌╌╌╌╌╌╌╌╮ │ ║ Server-to-Client Direct communication
║ ╎ │ ╎ ┏━━━━━━┓┓┓ ╎ │ ║ ╭────────────────╮╮╮
║ ╎ │ ╎ ┃ TCP ┃┃┃ ╎─────────────────│───║─────────────│ Client Devices │││
║ ╎ │ ╎ ┗━━━━━━┛┛┛ ╎ │ ║ ╰────────────────╯╯╯
║ ╎ │ ╰╌╌╌╌╌╌╌╌╌╌╌╌╌╌╯ │ ║
║ ╎ │ │ ║
║ ╎ └─────────────────────────────────────────┘ ║
╚══════════════════════════════════════════════════════════════════╝
╎
╎
┌──────────────┐┐┐ Diarkis does not authenticate users by design.
│ API Servers │││ It relies on the existing user authentication to authenticate the users before connecting to Diarkis server cluster.
└──────────────┘┘┘
User Connection Flow
The diagram below shows the flow of the user starting the connection with Diarkis server cluster.
┊ ┊
╭───────────────╮ ┌────────────────────┐ ┊ ╔═══════════════╗ ┊ ┏━━━━━━━━━━━━━━┓ ┏━━━━━━━━━━━━━━━━━┓
│ Client Device │ │ Application Server │ ┊ ║ Load balancer ║ ┊ ┃ Diarkis HTTP ┃ ┃ Diarkis UDP/TCP ┃
╰───────────────╯ └────────────────────┘ ┊ ╚═══════════════╝ ┊ ┗━━━━━━━━━━━━━━┛ ┗━━━━━━━━━━━━━━━━━┛
│ │ ┊ ║ ┊ │ │
├───────────▶︎[ User Authentication ] ┊ ║ ┊ │ │
│ │ ┊ ║ ┊ │ │
│ ├───────────────────────▶︎╠══════════▶︎[ Endpoint Request ] │
│ │ ┊ ║ ┊ │ │
│ │ ┊ ║ ┊ ├────────────▶︎[ User Creation ]
│ │ ┊ ║ ┊ │ │
│ [ UDP/TCP Endpoint ]◀︎═════════════╣◀︎───────────────────┤ │
│ │ ┊ ║ ┊ │ │
[ UDP/TCP Endpoint ]◀︎───────────────┤ ┊ ║ ┊ │ │
│ │ ┊ ║ ┊ │ │
├───────────────────────────────────────────────────────────────────────────────▶︎[ UDP/TCP Direct Connection ]
│ │ ┊ ║ ┊ │ │
▽ ▽ ┊ ▽ ┊ ▽ ▽
┊ ┊
Setting Up Diarkis Server
Starter package of Diarkis helps you to set up Diarkis server by simply defining configurations.
import "github.com/Diarkis/diarkis/diarkisexec"
HTTP Server Example
logConfigPath := "/path/to/config/file/log.json"
meshConfigPath := ""
diarkisexec.SetupDiarkis(logConfigPath, meshConfigPath, &diarkisexec.Modules{
DM: &diarkisexec.Options{ ConfigPath: "/path/to/config/file/dm.json" },
Field: &diarkisexec.Options{ ConfigPath: "/path/to/config/file/field.json" },
MatchMaker: &diarkisexec.Options{ ConfigPath: "/path/to/config/file/matchmaker.json" },
})
// If we use DIARKIS_HTTP_SERVER_CONFIG_PATH=$(http server config path) env, we do not need to call diarkisexec.SetupDiarkisHTTPServer()
diarkisexec.SetupDiarkisHTTPServer("/path/to/config/file/http.json")
diarkisexec.StartDiarkis()
UDP Server Example
logConfigPath := "/path/to/config/file/log.json"
meshConfigPath := ""
diarkisexec.SetupDiarkis(logConfigPath, meshConfigPath, &diarkisexec.Modules{
DM: &diarkisexec.Options{ ConfigPath: "/path/to/config/file/dm.json", ExposeCommands: true },
Field: &diarkisexec.Options{ ConfigPath: "/path/to/config/file/field.json", ExposeCommands: true },
Group: &diarkisexec.Options{ ConfigPath: "/path/to/config/file/group.json", ExposeCommands: true },
MatchMaker: &diarkisexec.Options{ ConfigPath: "/path/to/config/file/matchmaker.json", ExposeCommands: true },
Room: &diarkisexec.Options{},
Session: &diarkisexec.Options{},
})
// If we use DIARKIS_UDP_SERVER_CONFIG_PATH=$(udp server config path) env, we do not need to call diarkisexec.SetupDiarkisUDPServer()
diarkisexec.SetupDiarkisUDPServer("/path/to/config/file/udp.json")
diarkisexec.StartDiarkis()
TCP Server Example
logConfigPath := "/path/to/config/file/log.json"
meshConfigPath := ""
diarkisexec.SetupDiarkis(logConfigPath, meshConfigPath, &diarkisexec.Modules{
DM: &diarkisexec.Options{ ConfigPath: "/path/to/config/file/dm.json", ExposeCommands: true },
Field: &diarkisexec.Options{ ConfigPath: "/path/to/config/file/field.json", ExposeCommands: true },
Group: &diarkisexec.Options{ ConfigPath: "/path/to/config/file/group.json", ExposeCommands: true },
MatchMaker: &diarkisexec.Options{ ConfigPath: "/path/to/config/file/matchmaker.json", ExposeCommands: true },
Room: &diarkisexec.Options{ ExposeCommands: true },
Session: &diarkisexec.Options{ ExposeCommands: true },
})
// If we use DIARKIS_TCP_SERVER_CONFIG_PATH=$(tcp server config path) env, we do not need to call diarkisexec.SetupDiarkisTCPServer()
diarkisexec.SetupDiarkisTCPServer("/path/to/config/file/tcp.json")
diarkisexec.StartDiarkis()
Setting Up Diarkis Server (HTTP, UDP, or TCP) via Environment Variable
Starter allows you to setup Diarkis server
by giving an environmental variable instead of calling SetupDiarkisHTTPServer, SetupDiarkisUDPServer, or SetupDiarkisTCPServer.
[IMPORTANT] If you use either DIARKIS_HTTP_SERVER_CONFIG_PATH, DIARKIS_UDP_SERVER_CONFIG_PATH, or DIARKIS_TCP_SERVER_CONFIG_PATH,
you do NOT need to call SetupDiarkisHTTPServer, SetupDiarkisUDPServer, or SetupDiarkisTCPServer.
Example:
# Start the server as Diarkis HTTP server
DIARKIS_HTTP_SERVER_CONFIG_PATH=/configs/http/main.json ./remote_bin/http
Valid Environment Variables For the Server
┌─────────────────────────────────┬──────────────────────────────────────────┐
│ DIARKIS_HTTP_SERVER_CONFIG_PATH │ Setup the server as Diarkis HTTP server. │
├─────────────────────────────────┼──────────────────────────────────────────┤
│ DIARKIS_UDP_SERVER_CONFIG_PATH │ Setup the server as Diarkis UDP server. │
├─────────────────────────────────┼──────────────────────────────────────────┤
│ DIARKIS_TCP_SERVER_CONFIG_PATH │ Setup the server as Diarkis TCP server. │
└─────────────────────────────────┴──────────────────────────────────────────┘
Declaring Custom Command Handlers
Diarkis Servers (UDP and TCP) allows you to define your own custom commands and their handlers on the server to be invoked by the client.
You must use SetServerCommandHandler(ver uint8, cmd uint16, handler CommandHandler) BEFORE invoking diarkisexec.StartDiarkis().
Example:
var ver uint8 = 10
var cmd uint16 = 100
func main() {
logConfigPath := "/path/to/config/file/log.json"
meshConfigPath := ""
diarkisexec.SetupDiarkis(logConfigPath, meshConfigPath, &diarkisexec.Modules{
DM: &diarkisexec.Options{ ConfigPath: "/path/to/config/file//configs/dm.json", ExposeCommands: true },
Field: &diarkisexec.Options{ ConfigPath: "/path/to/config/file//configs/field.json", ExposeCommands: true },
Group: &diarkisexec.Options{ ConfigPath: "/path/to/config/file//configs/group.json", ExposeCommands: true },
MatchMaker: &diarkisexec.Options{ ConfigPath: "/path/to/config/file//configs/matchmaker.json", ExposeCommands: true },
Room: &diarkisexec.Options{},
Session: &diarkisexec.Options{},
})
// If we use DIARKIS_UDP_SERVER_CONFIG_PATH=$(udp server config path) env, we do not need to call diarkisexec.SetupDiarkisUDPServer()
diarkisexec.SetupDiarkisUDPServer("/path/to/config/file/udp.json")
diarkisexec.SetServerCommandHandler(ver, cmd, helloWorld)
diarkisexec.StartDiarkis()
}
func helloWorld(ver uint8, cmd uint16, payload []byte, userData *user.User, next func(error)) {
userData.ServerRespond([]byte("Hello World"), ver, cmd, diarkisexec.ResponseStatusOk(), true)
next(nil)
})
Declaring Custom Mesh Command Handlers (Server-to-Server Command handlers)
Diarkis Server allows you to define your own custom mesh commands (internal server-to-server commands).
You must use SetMeshCommandHandler(cmd uint16, handler MeshCommandHandler) BEFORE invoking diarkisexec.StartDiarkis().
Example:
var cmd uint16 = 20000
func main() {
logConfigPath := "/path/to/config/file/log.json"
meshConfigPath := ""
diarkisexec.SetupDiarkis(logConfigPath, meshConfigPath, &diarkisexec.Modules{
DM: &diarkisexec.Options{ ConfigPath: "/path/to/config/file//configs/dm.json", ExposeCommands: true },
Field: &diarkisexec.Options{ ConfigPath: "/path/to/config/file//configs/field.json", ExposeCommands: true },
Group: &diarkisexec.Options{ ConfigPath: "/path/to/config/file//configs/group.json", ExposeCommands: true },
MatchMaker: &diarkisexec.Options{ ConfigPath: "/path/to/config/file//configs/matchmaker.json", ExposeCommands: true },
Room: &diarkisexec.Options{},
Session: &diarkisexec.Options{},
})
// If we use DIARKIS_UDP_SERVER_CONFIG_PATH=$(udp server config path) env, we do not need to call diarkisexec.SetupDiarkisUDPServer()
diarkisexec.SetupDiarkisUDPServer("/path/to/config/file/udp.json")
diarkisexec.SetMeshCommandHandler(cmd, handleExampleMeshCommand)
diarkisexec.StartDiarkis()
}
func handleExampleMeshCommand(req map[string]interface{}) ([]byte, error) {
hello, ok := util.ToString(req["hello"])
if !ok {
return nil, util.NewError("Invalid request data")
}
helloWorld := util.StrConcat(hello, "world")
// create response
resp := make(map[string]interface{})
resp["message"] = helloWorld
return diarkisexec.CreateReturnBytes(resp)
}
Environment Variables
Diarkis server has many environment variables to control how the server behaves.
┌───────────────────────────┬─────────┬─────────────────────────────────────────────────────────────────────────────────────────┬──────────┐
│ Environment Variable Name │ Values │ Description │ Required │
├───────────────────────────┼─────────┼─────────────────────────────────────────────────────────────────────────────────────────┼──────────┤
│ DIARKIS_CLOUD_ENV │ GCP │ Auto-assign public IP address to UDP and TCP server for Google Cloud. │ ○ │
│ │ AWS │ Auto-assign public IP address to UDP and TCP server for AWS. │ │
│ │ AZURE │ Auto-assign public IP address to UDP and TCP server for Microsoft Azure. │ │
│ │ TENCENT │ Auto-assign public IP address to UDP and TCP server for Tencent Cloud. │ │
│ │ ALIBABA │ Auto-assign public IP address to UDP and TCP server for Alibaba Cloud. │ │
│ │ LINODE │ Auto-assign public IP address to UDP and TCP server for Linode. │ │
│ │ $(host) │ Manually assigns a hostname or IP address to the server. │ │
├───────────────────────────┼─────────┼─────────────────────────────────────────────────────────────────────────────────────────┼──────────┤
│ DIARKIS_SHUTDOWN_TIMEOUT │ $(sec) │ Configures the wait time in seconds to shutdown after receiving SIGTERM. │ △ │
│ │ │ Default is 10 seconds. │ │
│ │ │ Time out value configured here must match Kubernetes' terminationGracePeriodSeconds. │ │
├───────────────────────────┼─────────┼─────────────────────────────────────────────────────────────────────────────────────────┼──────────┤
│ DIARKIS_SERVER_TYPE │ $(type) │ Assigns custom server type to the server. Default is either HTTP, UDP, or TCP. │ │
│ │ │ This is the server type HTTP API of /endpoint/type/$(server_type)/user/$(user_id) uses. │ │
├───────────────────────────┼─────────┼─────────────────────────────────────────────────────────────────────────────────────────┼──────────┤
│ DIARKIS_USE_STRUCT_ERR │ TRUE │ If configured, all errors of built-in server commands will be structured errors. │ │
│ │ │ A structured error contains an error code (uint32) and an error message string. │ │
├───────────────────────────┼─────────┼─────────────────────────────────────────────────────────────────────────────────────────┼──────────┤
│ DIARKIS_JSON_LOG │ TRUE │ If configured, all Diarkis logging will be JSON formatted. │ │
├───────────────────────────┼─────────┼─────────────────────────────────────────────────────────────────────────────────────────┼──────────┤
│ DIARKIS_APP_NAME │ $(name) │ Assigns a custom application name to the server to group servers with the same name. │ │
│ │ │ If servers with different names are connected to the same MARS, │ │
│ │ │ they will not see each other effectively creating different Diarkis cluster. │ │
├───────────────────────────┼─────────┼─────────────────────────────────────────────────────────────────────────────────────────┼──────────┤
│ DIARKIS_CLIENT_KEY │ $(key) │ If configured, the server requires the key to be sent from all connected clients. │ │
│ │ │ If client key is not configured, the server does not require the key to be sent. │ │
└───────────────────────────┴─────────┴─────────────────────────────────────────────────────────────────────────────────────────┴──────────┘
▶︎ DIARKIS_CLOUD_ENV is required for each server to assign correct public hostname/IP address.
▶︎ DIARKIS_SHUTDOWN_TIMEOUT is not required,
however, it must be configured to the same value as kubernetes' terminationGracePeriodSeconds configuration.
SIGUSR1 and SIGUSR2
Diarkis server captures SIGUSR1 and SIGUSR2 signal and have the server perform pre-defined custom operations at runtime.
Below is the step by step instruction of how to trigger pre-defined custom operations:
1. Create a file called DIARKIS_SIGUSR1 or DIARKIS_SIGUSR2 under /tmp/ directory.
2. In the file, write the pre-defined operation name WITHOUT a line break.
3. Send either SIGUSR1 or SIGUSR2 signal to the server.
▶︎ Example of pre-defined operation implementation
// This is the operation name that goes into DIARKIS_SIGUSR1 file
taskName := "ExampleOperation"
// The callback does not have to be a closure function...
diarkis.OnSIGUSR1(taskName, func() {
fmt.Println("Diarkis server received SIGUSR1 signal and task is ExampleOperation")
})
Built-in SIGUSR1 Operations
There are a few built-in SIGUSR1 operations that you may you out-of-the-box.
▶︎ TaskName: Debug
This operation is a toggle. Call it once will enable it and calling it again will disable it.
When "Debug" is enabled, Go's profiler is enabled. You may access profiler's internal server
at http://127.0.0.1:6060 (Assuming port 6060 is not already being used...).
Change Log Level For A Specific Logger Name at Runtime
Diarkis logger allows you to change a specific logger's log level in runtime as well.
Logger name is the string output that is wrapped in < and >. If you see <SERVER>, then logger name is SERVER.
Below is the step by step operation to change log level by logger name in runtime.
1. Create a signal command file named DIARKIS_SIGUSR1 under /tmp/ directory. It should look like this: /tmp/DIARKIS_SIGUSR1
▶︎ Enable runtime log level change by logger name
DIARKIS_SIGUSR1 file must contain the following to enable runtime log level change:
LogLevelChangeByName
Enable
$(logger_name)
$(log_level)
Example:
The example below will enable verbose level of logging just for "ROOM" logs.
LogLevelChangeByName
Enable
ROOM
Verbose
▶︎ Disable runtime log level change by logger name
DIARKIS_SIGUSR1 file must contain the following to disable runtime log level change:
LogLevelChangeByName
Disable
Change Log Level Globally At Runtime
You may change log level for all logging at runtime.
[IMPORTANT] If LogLevelChangeByName is enabled, it takes the highest priority for the specified log name.
▶︎ TaskName: LogLevel:Verbose
This operation will change Diarkis logger's log level at runtime to verbose.
▶︎ TaskName: LogLevel:Network
This operation will change Diarkis logger's log level at runtime to network.
▶︎ TaskName: LogLevel:Sys
This operation will change Diarkis logger's log level at runtime to sys.
▶︎ TaskName: LogLevel:Debug
This operation will change Diarkis logger's log level at runtime to debug.
▶︎ TaskName: LogLevel:Info
This operation will change Diarkis logger's log level at runtime to info.
▶︎ TaskName: LogLevel:Error
This operation will change Diarkis logger's log level at runtime to error.
▶︎ TaskName: LogLevel:Fatal
This operation will change Diarkis logger's log level at runtime to fatal.
Rotate Log Level Globally
▶︎ TaskName: LogLevelChange
This operation will change Diarkis logger's log level at runtime. Every time this operation is called the log level changes.
[IMPORTANT] If LogLevelChangeByName is enabled, it takes the highest priority for the specified log name.
Below is the order of log level change:
╭─────────╮ ╭─────────╮ ╭─────────╮ ╭─────────╮ ╭─────────╮
╔═▶︎│ Verbose │▶︎│ Network │▶︎│ Sys │▶︎│ Debug │▶︎│ Info │══╗
║ ╰─────────╯ ╰─────────╯ ╰─────────╯ ╰─────────╯ ╰─────────╯ ║
╚═══════════════════════════════════════════════════════════════╝
▶︎ TaskName: VaultDump
This operation dumps users, room, and group data of the server into stdout stream.
▶︎ MatchMakerDump
This operation dumps MatchMaker data of the server into stdout stream.
Execute Custom Operations When Server Started and Ready
You may assign your custom operations to be executed when the server is started and ready.
▶︎ Example
diarkis.OnReady(func(next func(err error)) {
// Do something amazing because the server is ready.
// Make sure to call next to move on.
// Passing an error to next will abort the server with an error.
next(nil)
})
Execute Custom Operations When Shutting Down the Server
You may assign your custom operations to be executed when the server shuts down.
The server will "wait" for those operations to finish before shutting down.
▶︎ Example
diarkis.OnTerminate(func(next func(err error)) {
// Do something important before going away.
// Like closing connections to DB etc.
// Make sure to call next to move on.
next(nil)
})
Enable or Disable pprof in runtime
By sending SIGUSR1 to Diarkis server process, you may toggle pprof without interrupting the server process.
Every time you send SIGUSR1 signal it enable/disable pprof.
1. Create a file /tmp/DIARKIS_SIGSUR1
2. Write Debug into the /tmp/DIARKIS_SIGUSR1 file
3. Send SIGUSR1 signal by executing kill -s SIGUSR1 $(PID)
▶︎ How to use profiler
When debug pprof is enabled, the server opens 127.0.0.1:6060/debug/pprof endpoint:
Profile CPU usage:
curl 127.0.0.1:6060/debug/pprof/profile > cpu.profile
Read CPU profile:
go tool pprof cpu.profile
Profile memory allocation:
curl 127.0.0.1:6060/debug/pprof/heap > heap.profile
Read memory allocation profile:
go tool pprof heap.profile
Trace:
curl 127.0.0.1:6060/debug/pprof/trace > trace.profile
Read trace profile:
go tool trace trace.profile
Dump currently held user, room, and group data into stdout stream
By sending SIGUSR1 to Diarkis server process, you may dump the said data without interrupting the server process.
1. Create a file /tmp/DIARKIS_SIGUSR1
2. Write VaultDump into the /tmp/DIARKIS_SIGUSR1 file
3. Send SIGUSR1 signal by executing kill -s SIGUSR1 $(PID)
Dump MatchMaker Data
By sending SIGUSR1 to Diarkis server process, you may dump the MatchMaker data into stdout stream.
1. Create a file /tmp/DIARKIS_SIGUSR1
2. Write MatchMakerDump into the /tmp/DIARKIS_SIGUSR1 file
3. Send SIGUSR1 signal by executing kill -s SIGUSR1 $(PID)
Health Check Probe
Diarkis server comes with health check probe.
This probe will check UDP/RUDP's public facing network availability and internal network availability.
▶︎ How To Execute the Probe
The probe requires a configuration JSON file in the following path:
The JSON file must be named health-check.json.
bin/tools/configs/health-check.json
▶︎▶︎ Test Public Network Availability (UDP/RUDP server ONLY)
When the Diarkis server is running, the server places a file that contains its public address and port.
/tmp/DIARKIS_PUBLIC_ADDR
Use the file shown above to test public network:
# Health check probe binary # Text file that contains public address and port # Flag for public network probe
./health-check `cat /tmp/DIARKIS_PUBLIC_ADDR` out
▶︎▶︎ Test Internal Network Availability (All Diarkis servers)
When the Diarkis server is running, the server places a file that contains its internal address and port.
/tmp/DIARKIS_MESH_ADDR
Use this file shown above to test internal network:
# Health check probe binary # Text file that contains internal address and port # Flag for internal network probe
./health-check `cat /tmp/DIARKIS_MESH_ADDR` in
▶︎▶︎ Test Internal Network Availability (All Diarkis servers) And Communication With MARS
When the Diarkis server is running, the server places a file that contains its internal address and port.
/tmp/DIARKIS_MESH_ADDR
Use this file shown above to test internal network and communication status with MARS:
# Health check probe binary # Text file that contains internal address and port # Flag for internal network + MARS probe
./health-check `cat /tmp/DIARKIS_MESH_ADDR` mars
Use Environment Variables For Configurations
Diarkis uses JSON formatted configuration files to configure Diarkis itself and modules.
These configuration files may have a spacial tags as configuration values to be replaced by environment variables on server start.
▶︎ Format
The placeholders in your configuration files must follow the format shown below:
{$DIARKIS_...}
▶︎ Example
DIARKIS_EXAMPLE_HELLO=HELLO
DIARKIS_EXAMPLE_NUMBER=1000
{
"helloWorld":"{$DIARKIS_EXAMPLE_HELLO}",
"number": {$DIARKIS_EXAMPLE_NUMBER}
}
The above example will convert the configurations as shown below:
DIARKIS_EXAMPLE_HELLO=HELLO
DIARKIS_EXAMPLE_NUMBER=1000
{
"helloWorld":"HELLO",
"number": 1000
}