dfx 1.0.0-alpha

A FIX protocol implementation
Documentation
# DFX

A FIX protocol engine.

## Goals

- [x] Runtime Message verification
- [x] Read config from file
- [x] Pass the test suite available
  - [x] FIX40
  - [x] FIX41
  - [x] FIX42
  - [x] FIX43
  - [x] FIX44
    - [x] FIX: fix44::test_resend_repeating_group
      > Now the tests compares ordered fields, so the response match the expectation but are not exactly the same.
  - [x] FIXT11
    - [x] FIX50
    - [x] FIX50SP1
    - [x] FIX50SP2
  - [ ] FUTURE
    > IGNORED!
    > Currently not supported by Quickfix or Quickfix/N
  - [x] MISC
- [x] SSL / TLS
- [x] FileStore for messages
- [x] FileLogger
  - [x] Similar to quickfix
  - [x] [`log`](https://docs.rs/log/latest/log/) Logger

## WIP

- Add inline and doc comments
 - Doc External
 - Doc Internal
 - Inline
 
## TODO
- Add message factory from data dictionary.
- Codegen static data dictionary from xml.
- Replace with Traits where possible
- Allow compile time message definitions
- MessageCracker
- Cleanup session.rs
  - Simplify message handling
  - Simplify next / next_msg()
- Generate report from test suite (For easier tracking)

## Credits
Heavily derived / inspired from [QuickfixN](https://github.com/connamara/quickfixn/)

## Examples
```rust
use dfx::{
    connection::SocketAcceptor,
    session::{Session, SessionSettings},
    message_store::{DefaultStoreFactory, MemoryStoreFactory},
    data_dictionary_provider::DefaultDataDictionaryProvider,
    logging::PrintlnLogFactory,
    message::DefaultMessageFactory,
    session::FromAppError,
    session::ApplicationError,
    session::LogonReject,
    session::DoNotAccept,
    message::Message,
};

#[derive(Clone, Default)]
struct Application;

impl dfx::session::Application for Application {

    fn on_create(&mut self, _session_id: &dfx::session_id::SessionId) -> Result<(), DoNotAccept> {
        println!("TestApplication: {}", _session_id);
        Ok(())
    }

    fn on_logon(&mut self, _session_id: &dfx::session_id::SessionId) -> Result<(), LogonReject> {
        println!("TestApplication Logon: {}", _session_id);
        Ok(())
    }

    fn on_logout(&mut self, _session_id: &dfx::session_id::SessionId) -> Result<(), ApplicationError> {
        println!("TestApplication Logout: {}", _session_id);
        Ok(())
    }

    fn to_admin(
        &mut self,
        message: Message,
        _session_id: &dfx::session_id::SessionId,
    ) -> Result<Message, dfx::field_map::FieldMapError> {
        println!("TestApplication To Admin: {}", _session_id);
        Ok(message)
    }

    fn from_admin(
        &mut self,
        _message: &Message,
        _session_id: &dfx::session_id::SessionId,
    ) -> Result<(), dfx::field_map::FieldMapError> {
        println!("TestApplication From Admin: {}", _session_id);
        Ok(())
    }

    fn to_app(
        &mut self,
        _message: &mut Message,
        _session_id: &dfx::session_id::SessionId,
    ) -> Result<(), ApplicationError> {
        println!("TestApplication To App: {}", _session_id);
        Ok(())
    }

    fn from_app(
        &mut self,
        message: &Message,
        session_id: &dfx::session_id::SessionId,
    ) -> Result<(), FromAppError> {
        println!("TestApplication From App: {}", session_id);
        // TODO Do something here
        Ok(())
    }
}

let app = Application::default();
// TODO Use the following to read it from file:
// let session_settings = SessionSettings::from_file("fix.cfg").unwrap();
let session_settings = SessionSettings::default();
let mut acceptor = SocketAcceptor::new(
    &session_settings,
    app,
    DefaultStoreFactory::new(&session_settings),
    DefaultDataDictionaryProvider::new(),
    PrintlnLogFactory::new(),
    DefaultMessageFactory::new(),
);

acceptor.start();
```