TimelordUK / jspurefix

native typescript FIX engine
MIT License
58 stars 27 forks source link

Logon with custom tags #39

Closed bekee closed 2 years ago

bekee commented 2 years ago

I've been able to setup custom tags, generated the types and assigned them to dictionary but unfortunately the server requires specific tags to be added on the logon. How can be able to add custom tags to the logon.

Sample json { "application": { "reconnectSeconds": 10, "type": "initiator", "name": "test_client", "tcp": { "host" : "199.29.44.127", "port": 10400 }, "protocol": "ascii", "dictionary": "../../FIX5.0NSE.xml" }, "Username": "MRIXMGR", "Password": "Passwordn9s%k", "EncryptMethod": 0, "ResetSeqNumFlag": true, "DefaultApplVerID":"8", "HeartBtInt": 30, "SenderCompId": "TFL", "TargetCompID": "XTRM", "TargetSubID": "fix", "Text": "logon", "BeginString": "FIXT.1.1" }

The missing custom tags are Text and DefaultApplVerID when the app tries to logon to the server. So it triggers missing tag (58)

Please anyone help me with this. @TimelordUK

TimelordUK commented 2 years ago

I will try and check something in next day or so.

Idea would be too take something like this

https://github.com/TimelordUK/jspurefix/blob/master/src/sample/tcp/recovering-skeleton/app.ts

and override the message factory with your own derived code that implements logon with new tag.

That being said I have not tried it yet but this is why dependency injection was used to register basically any class where system can be customised.

In this method you are given the container and you would register a new factory using token message factory.

TimelordUK commented 2 years ago

I should add your version of this function does not need to be this complicated as example. You only need to override factory and register your session object.

bekee commented 2 years ago

I appreciate your effort and quick response, I hope to see the update soon

bekee commented 2 years ago

I tried implementing your suggestion but got stocked because I didn't understand the classes to override. Any hint can help.

TimelordUK commented 2 years ago

I will try check in later idea is to inherit from

https://github.com/TimelordUK/jspurefix/blob/master/src/transport/ascii/ascii-session-msg-factory.ts

in your own project define a new factory override the logon method

if this seems too complex another possible way is if you look at this class it calls the mutator method which you can override.

So from config object in your client somewhere at startup you register a callback on mutate function and it will give you message type and the logon object. You should then be able to add your additional tags in your method which returns and then sends to server.

TimelordUK commented 2 years ago

Look in unit tests for places where mutator is used to change an object

TimelordUK commented 2 years ago

https://github.com/TimelordUK/jspurefix/blob/master/src/test/ascii/session.test.ts

bekee commented 2 years ago

I'll get back to you on it thanks

TimelordUK commented 2 years ago

I have not had much time on this but if you look at

https://github.com/TimelordUK/jspf-md-demo

we have added our own message factory which you can add your tags to logon method

import 'reflect-metadata'

import { IJsFixConfig, SessionLauncher, DITokens, FixSession, ISessionDescription, JsFixConfig } from 'jspurefix'
import { DependencyContainer } from 'tsyringe'
import { MDClient } from './md-client'
import { MDServer } from './md-server'
import { MsgFact } from './msg-fact'

class AppLauncher extends SessionLauncher {
  public constructor (
    client: string = '../../data/session/test-initiator.json',
    server: string = '../../data/session/test-acceptor.json') {
    super(client, server)
    this.root = __dirname
  }

  private customFactory (sessionContainer: DependencyContainer): IJsFixConfig {
    const d = sessionContainer.resolve<ISessionDescription>(DITokens.ISessionDescription)
    const oldConfig = sessionContainer.resolve<IJsFixConfig>(DITokens.IJsFixConfig)
    // our own factory which we can use to add custom logon tags
    const fact = new MsgFact(d)
    // clear container as set up by system
    sessionContainer.clearInstances()
    // re-register base system
    this.sessionContainer.registerGlobal()
    // add back original description
    sessionContainer.registerInstance(DITokens.ISessionDescription, d)
    // register our own session factory with our own logon
    sessionContainer.registerInstance(DITokens.ISessionMsgFactory, fact)
    // now re-create a new config using our own factory
    const newConfig = new JsFixConfig(fact, oldConfig.definitions, d, oldConfig.delimiter, oldConfig.logFactory)
    return newConfig
  }

  protected override registerApplication (sessionContainer: DependencyContainer): void {
    const newConfig = this.customFactory(sessionContainer)
    const isInitiator = this.isInitiator(newConfig.description)
    if (isInitiator) {
      sessionContainer.register<FixSession>(DITokens.FixSession, {
        useClass: MDClient
      })
    } else {
      sessionContainer.register<FixSession>(DITokens.FixSession, {
        useClass: MDServer
      })
    }
    this.sessionContainer.registerSession(newConfig, sessionContainer)
  }

  /*
  protected override makeFactory (config: IJsFixConfig): EngineFactory {
    const isInitiator = this.isInitiator(config.description)
    return {
      makeSession: () => isInitiator ?
        new MDClient(config) :
        new MDServer(config)
    } as EngineFactory
  }*/
}

const l = new AppLauncher()
l.exec()
bekee commented 2 years ago

Thanks a lot, this worked for me