192 lines
5.2 KiB
Go
192 lines
5.2 KiB
Go
// Copyright (c) quickfixengine.org All rights reserved.
|
|
//
|
|
// This file may be distributed under the terms of the quickfixengine.org
|
|
// license as defined by quickfixengine.org and appearing in the file
|
|
// LICENSE included in the packaging of this file.
|
|
//
|
|
// This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING
|
|
// THE WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A
|
|
// PARTICULAR PURPOSE.
|
|
//
|
|
// See http://www.quickfixengine.org/LICENSE for licensing information.
|
|
//
|
|
// Contact ask@quickfixengine.org if any conditions of this licensing
|
|
// are not clear to you.
|
|
|
|
package quickfix
|
|
|
|
import (
|
|
"bufio"
|
|
"errors"
|
|
"fmt"
|
|
"io"
|
|
"regexp"
|
|
|
|
"quantex.com/qfixpt/quickfix/config"
|
|
)
|
|
|
|
// The Settings type represents a collection of global and session settings.
|
|
type Settings struct {
|
|
globalSettings *SessionSettings
|
|
sessionSettings map[SessionID]*SessionSettings
|
|
}
|
|
|
|
// Init initializes or resets a Settings instance.
|
|
func (s *Settings) Init() {
|
|
s.globalSettings = NewSessionSettings()
|
|
s.sessionSettings = make(map[SessionID]*SessionSettings)
|
|
}
|
|
|
|
func (s *Settings) lazyInit() {
|
|
if s.globalSettings == nil {
|
|
s.Init()
|
|
}
|
|
}
|
|
|
|
// NewSettings creates a Settings instance.
|
|
func NewSettings() *Settings {
|
|
s := &Settings{}
|
|
s.Init()
|
|
return s
|
|
}
|
|
|
|
func sessionIDFromSessionSettings(globalSettings *SessionSettings, sessionSettings *SessionSettings) SessionID {
|
|
sessionID := SessionID{}
|
|
|
|
for _, settings := range []*SessionSettings{globalSettings, sessionSettings} {
|
|
if settings.HasSetting(config.BeginString) {
|
|
sessionID.BeginString, _ = settings.Setting(config.BeginString)
|
|
}
|
|
|
|
if settings.HasSetting(config.TargetCompID) {
|
|
sessionID.TargetCompID, _ = settings.Setting(config.TargetCompID)
|
|
}
|
|
|
|
if settings.HasSetting(config.TargetSubID) {
|
|
sessionID.TargetSubID, _ = settings.Setting(config.TargetSubID)
|
|
}
|
|
|
|
if settings.HasSetting(config.TargetLocationID) {
|
|
sessionID.TargetLocationID, _ = settings.Setting(config.TargetLocationID)
|
|
}
|
|
|
|
if settings.HasSetting(config.SenderCompID) {
|
|
sessionID.SenderCompID, _ = settings.Setting(config.SenderCompID)
|
|
}
|
|
|
|
if settings.HasSetting(config.SenderSubID) {
|
|
sessionID.SenderSubID, _ = settings.Setting(config.SenderSubID)
|
|
}
|
|
|
|
if settings.HasSetting(config.SenderLocationID) {
|
|
sessionID.SenderLocationID, _ = settings.Setting(config.SenderLocationID)
|
|
}
|
|
|
|
if settings.HasSetting(config.SessionQualifier) {
|
|
sessionID.Qualifier, _ = settings.Setting(config.SessionQualifier)
|
|
}
|
|
}
|
|
|
|
return sessionID
|
|
}
|
|
|
|
// ParseSettings creates and initializes a Settings instance with config parsed from a Reader.
|
|
// Returns error if the config is has parse errors.
|
|
func ParseSettings(reader io.Reader) (*Settings, error) {
|
|
s := NewSettings()
|
|
|
|
scanner := bufio.NewScanner(reader)
|
|
blankRegEx := regexp.MustCompile(`^\s*$`)
|
|
commentRegEx := regexp.MustCompile(`^#.*`)
|
|
defaultRegEx := regexp.MustCompile(`^\[(?i)DEFAULT\]\s*$`)
|
|
sessionRegEx := regexp.MustCompile(`^\[(?i)SESSION\]\s*$`)
|
|
settingRegEx := regexp.MustCompile(`^([^=]*)=(.*)$`)
|
|
|
|
var settings *SessionSettings
|
|
|
|
lineNumber := 0
|
|
for scanner.Scan() {
|
|
lineNumber++
|
|
line := scanner.Text()
|
|
|
|
switch {
|
|
case commentRegEx.MatchString(line) || blankRegEx.MatchString(line):
|
|
continue
|
|
|
|
case defaultRegEx.MatchString(line):
|
|
settings = s.GlobalSettings()
|
|
|
|
case sessionRegEx.MatchString(line):
|
|
if settings != nil && settings != s.GlobalSettings() {
|
|
if _, err := s.AddSession(settings); err != nil {
|
|
return nil, err
|
|
}
|
|
}
|
|
settings = NewSessionSettings()
|
|
|
|
case settingRegEx.MatchString(line):
|
|
parts := settingRegEx.FindStringSubmatch(line)
|
|
settings.Set(parts[1], parts[2])
|
|
|
|
default:
|
|
return s, fmt.Errorf("error parsing line %v", lineNumber)
|
|
}
|
|
}
|
|
|
|
if err := scanner.Err(); err != nil {
|
|
return s, err
|
|
}
|
|
|
|
if settings == nil || settings == s.GlobalSettings() {
|
|
return s, fmt.Errorf("no sessions declared")
|
|
}
|
|
_, err := s.AddSession(settings)
|
|
|
|
return s, err
|
|
}
|
|
|
|
// GlobalSettings are default setting inherited by all session settings.
|
|
func (s *Settings) GlobalSettings() *SessionSettings {
|
|
s.lazyInit()
|
|
return s.globalSettings
|
|
}
|
|
|
|
// SessionSettings return all session settings overlaying globalsettings.
|
|
func (s *Settings) SessionSettings() map[SessionID]*SessionSettings {
|
|
allSessionSettings := make(map[SessionID]*SessionSettings)
|
|
|
|
for sessionID, settings := range s.sessionSettings {
|
|
cloneSettings := s.globalSettings.clone()
|
|
cloneSettings.overlay(settings)
|
|
allSessionSettings[sessionID] = cloneSettings
|
|
}
|
|
|
|
return allSessionSettings
|
|
}
|
|
|
|
// AddSession adds Session Settings to Settings instance. Returns an error if session settings with duplicate sessionID has already been added.
|
|
func (s *Settings) AddSession(sessionSettings *SessionSettings) (SessionID, error) {
|
|
s.lazyInit()
|
|
|
|
sessionID := sessionIDFromSessionSettings(s.GlobalSettings(), sessionSettings)
|
|
|
|
switch sessionID.BeginString {
|
|
case BeginStringFIX40:
|
|
case BeginStringFIX41:
|
|
case BeginStringFIX42:
|
|
case BeginStringFIX43:
|
|
case BeginStringFIX44:
|
|
case BeginStringFIXT11:
|
|
default:
|
|
return sessionID, errors.New("BeginString must be FIX.4.0 to FIX.4.4 or FIXT.1.1")
|
|
}
|
|
|
|
if _, dup := s.sessionSettings[sessionID]; dup {
|
|
return sessionID, fmt.Errorf("duplicate session configured for %v", sessionID)
|
|
}
|
|
|
|
s.sessionSettings[sessionID] = sessionSettings
|
|
|
|
return sessionID, nil
|
|
}
|