...
Info |
---|
Inter-Process Communication (IPC) Handler has been available since the FIXEdge 6.18.0 release. |
Overview
The FIXEdge IPC Handler is a component of the FIXEdge Business Layer designed to facilitate communication between the server and third-party applications using IPC mechanisms such as Unix domain sockets and Windows named pipes. This interaction involves the exchange of FIX messages and auxiliary data from the Server to the Client, with the possibility of modified FIX messages being returned to the Server, enhanced with additional auxiliary data.
...
For the official protocol specification, see the IPC/client/protocol.md file available at in the FIXEdge - SDK package.
Data Exchange
In the data exchange phase, the Handler sends JSON-serialized FIX messages to the Client together with supplementary data that includes the clientTag and any additional auxiliary data. The Client must respond with a result code (0 for success) and additional reply data within a specified timeout:
...
The client must send its response within a defined timeframe (specified in microseconds). Failure to respond within this timeout period will be treated as an error.
...
this timeout period will be treated as an error.
...
Business Layer Configuration Options
All configurations for the IPC Handler are defined within the BL_Config.xml file as shown below:
Code Block |
---|
| <FIXEdge>
<DllHandlers>
<Handler Name="IPC1"
Description="IPC Handler"
DllName="./libIPCHandler-MD-x64.so"
ListenAddress="/tmp/unixsock"
ClientTag="ClientTagValue"
TimeoutUsec="100000"
ClientConnectionWaitTimeoutMsec="100"
AuxData="StaticIpc1AuxData"
AuxDataContextKeyName="ResultAuxDataKeyName"
/>
</DllHandlers>
<BusinessLayer>
<Rule Description="Sending to IPC client">
<Source Name="NORTH-FE"/>
<Action>
<HandlerAction Name="IPC1" AuxData="DynamicIpc1AuxData" TimeoutUsec="15000" AuxDataContextKeyName="AuxDataKvKey"/>
</Action>
</Rule>
</BusinessLayer>
</FIXEdge> |
|
...
To call a handler from JavaScript:
Code Block |
---|
| // Calling the IPC1 with the current FIX message, passing "HandlerAuxData" to the Client, binding the auxiliary data, sent by the client to the "IPC1_clientAuxData" key of the session KV storage.
handler("IPC1", [
["TimeoutUsec", "150000"],
["AuxData", "HandlerAuxData"],
["AuxDataContextKeyName", "AuxDataKvKey"]
]); |
|
...
Python FIXEdge server abstraction may require installing dependencies if specified in requirements.txt file. An example command that may be used is as follows:
Code Block |
---|
| python3 -m pip install -r requirements.txt |
|
...
This simple example for Linux only prints the received message to the standard output.
Code Block |
---|
| import sys
import json
from fixedge_ipc_server import fixedge_ipc_server_v1
if sys.version_info[0] < 3:
raise Exception("Python 3 is required for this code to run.")
server = fixedge_ipc_server_v1()
client_tag = ""
try:
client_tag = server.connect('/tmp/fixedge_unixdomainsocket_name')
except Exception as error:
print("Unable to connect due to:", error)
exit(1)
print('FixEdge server set up the client tag: ', client_tag)
while True:
fmr = {};
try:
fmr = server.recv_fix_message_request()
except Exception as error:
print("Unable to communicate due to:", error)
exit(1)
print(fmr)
server.reply_success('', '', '') |
|
...
A minimal FIXEdge BL_Config entry for Windows could look like this:
Code Block |
---|
| <Handler
Name="IPC1"
Description="IPC Handler"
DllName="IPCHandler-MD-x64.dll"
ListenAddress="\\.\pipe\fixedge_namedpipe_name"
/> |
|
Modifying the Incoming Message
Code Block |
---|
| import sys
import json
from fixedge_ipc_server import fixedge_ipc_server_v1
if sys.version_info[0] < 3:
raise Exception("Python 3 is required for this code to run.")
server = fixedge_ipc_server_v1()
client_tag = ""
try:
client_tag = server.connect('/tmp/fixedge_unixdomainsocket_name')
except Exception as error:
print("Unable to connect due to:", error)
exit(1)
print('FixEdge server set up the client tag: ', client_tag)
while True:
fmr = {};
try:
fmr = server.recv_fix_message_request()
except Exception as error:
print("Unable to communicate due to:", error)
exit(1)
message = json.loads(fmr['message'])
message['Body']['ListID'] = 'NewListID'
server.reply_success(json.dumps(message), '', '') |
|
Code Block |
---|
| import { FixEdgeIpcServerV1 } from './fixedge_ipc_server.mjs';
const fe = new FixEdgeIpcServerV1;
fe.on('error', (message) => {
console.log('FixEdge server communication error: ', message);
});
fe.on('end', () => {
console.log('FixEdge server closed connection.');
});
fe.on('clientTag', (clientTag) => {
console.log('FixEdge server set up the client tag: ' + clientTag);
});
fe.onMessage = (fixMessageRequest) => {
var msg = JSON.parse(fixMessageRequest.message);
msg.Body.ListID = 'NewListID';
fe.replySuccess(JSON.stringify(msg), '', '');
};
if (process.platform !== 'win32')
fe.connect('/tmp/fixedge_unixdomainsocket_name');
else
fe.connect('\\\\.\\pipe\\fixedge_namedpipe_name'); |
|
Using Custom FIX Parsers
Code Block |
---|
| # Usual FE server abstraction initialization is skipped
while True:
fmr = {};
try:
fmr = server.recv_fix_message_request()
except Exception as error:
print('Unable to communicate due to:', error)
exit(1)
message = json.loads(fmr['message'])
message['Header']['BeginString'] = 'FIX.4.3'
server.reply_success(json.dumps(message), 'FIX43', '') |
|
Code Block |
---|
| // Usual FE server abstraction initialization is skipped
fe.onMessage = (fixMessageRequest)=>{
var msg = JSON.parse(fixMessageRequest.message);
msg.Header.BeginString = 'FIX.4.3';
fe.replySuccess(JSON.stringify(msg), 'FIX43', '');
}; |
|
...
Auxiliary data can be transferred to a client using a BL_Config rule configuration using Handler.AuxData (to specify per-Handler auxiliary data) or Rule.AuxData (to specify per-Rule auxiliary data) XML elements. Yet another option is to use a Script XML element of BL_Config.xml, as follows:
Code Block |
---|
| <Action>
<Script Language="JavaScript" FileName="aux-data.js"/>
</Action> |
|
The aux-data.js file could look like this:
Code Block |
---|
| // Calling the IPC1 with the current FIX message, passing "Hello, Client!" to
// the Client, binding the auxiliary data sent by the client to the
// "IPC1_clientAuxData" key of the session KV storage.
var ctxKvKey = "IPC1_clientAuxData";
handler("IPC1", [
["AuxData", "Hello, Client!"],
["AuxDataContextKeyName", ctxKvKey]
]);
print(getCtxKV(ctxKvKey)); |
|
This example assumes that auxiliary data in the string format "Hello, Client!" is passed to the client. The client also passes its auxiliary data to the Handler. The Handler attaches the auxiliary data to the session context key-value store under the key IPC1_clientAuxData, which is later read by the getCtxKv call, as demonstrated in the following code excerpts:
Code Block |
---|
| # Usual FE server abstraction initialization is skipped
while True:
fmr = {}
try:
fmr = server.recv_fix_message_request()
except Exception as error:
print('Unable to communicate due to:', error)
exit(1)
print('Received from server:', fmr['auxData'])
server.reply_success('', '', '', 'Hello, Server!') |
|
Code Block |
---|
| // Usual FE server abstraction initialization is skipped
fe.onMessage = (fixMessageRequest) => {
console.log(fixMessageRequest.auxData);
fe.replySuccess(JSON.stringify(msg), '', 'Hello, Server!');
}; |
|
...