// New creates a new Telegraph instance func New(userHash string, hostnames []string, checkInterval time.Duration, maxConnectionCount int, keyPair cryptochain.KeyPair, debug bool) (Telegraph, error) { cc := cryptochain.NewCryptoChain(userHash, keyPair) // Protocol input will be used to process Newton protocol messages. pi := make(chan store.ProtocolInput) // Dispatcher routes messages and runs appropriate functions to process messages correctly. dp, err := dispatcher.New(userHash, hostnames, checkInterval, maxConnectionCount, cc, pi, debug) if err != nil { return nil, err } l := logger.New("telegraph") // Get a message store ms := store.NewMessageStore(1000 * time.Millisecond) t := &telegraph{ dispatcher: dp, pool: dp.GetPool(), log: l, protocolOutput: make(chan ProtocolMessage, 100), protocolInput: pi, messageStore: ms, cryptoChain: cc, waitGroup: &sync.WaitGroup{}, done: make(chan struct{}), } t.waitGroup.Add(3) go t.processCryptoOutput() go t.processProtocolOutput() go t.processProtocolInput() return t, nil }
func NewMessageStore(checkInterval time.Duration) MessageStore { m := make(map[int]chan ProtocolInput) pq := &PriorityQueue{} heap.Init(pq) l := logger.New("message-store") ms := messageStore{ m: m, checkInterval: checkInterval, done: make(chan struct{}), pq: pq, log: l, } go ms.expireObsoleteMessages() return &ms }
// New returns a new Dispatcher instade func New(userHash string, hostnames []string, checkInterval time.Duration, maxConnectionCount int, cc *cryptochain.CryptoChain, protocolInput chan store.ProtocolInput, debug bool) (Dispatcher, error) { p, err := pool.New(userHash, hostnames, checkInterval, maxConnectionCount, cc.ConnectionStore, debug) if err != nil { return nil, err } // Create a new logger l := logger.New("dispatcher") //if debug { // logger.SetLogLevel(log.DEBUG) //} d := &dispatcher{ Pool: p, log: l, cryptoChain: cc, protocolInput: protocolInput, } go d.dispatchIncomingMessages() return d, nil }
// New returns a new Pool instance. func New(userHash string, hostnames []string, checkInterval time.Duration, maxConnectionCount int, cs *cryptochain.ConnectionStore, debug bool) (Pool, error) { hc := len(hostnames) if hc == 0 { return nil, errors.New("We need hosts to run.") } hs := &hosts{ h: map[string]struct{}{}, } for _, host := range hostnames { hs.h[host] = struct{}{} } cn := &connections{ c: make(map[string]*connection), } // Create a new logger l := logger.New("pool") if debug { logger.SetLogLevel(log.DEBUG) } p := &pool{ maxConnectionCount: maxConnectionCount, checkInterval: checkInterval, hosts: hs, connections: cn, incomingMessages: make(chan []byte, 100), log: l, userHash: userHash, done: make(chan struct{}), cs: cs, } // Here we select hosts randomly to connect. // We must use unique hosts u := make(map[int]struct{}) // Determine the host limit limit := 0 if hc < maxConnectionCount { limit = hc } else { limit = maxConnectionCount } // Select the hosts c := 0 for { if len(hostnames) == 0 { return nil, ErrNoAvailableHost } r := rand.Intn(hc) if _, ok := u[r]; !ok { host := hostnames[r] // start a new newton connection // if it fails, the system tries to keep the number // at a constant value after initialization. err := p.newConnection(host) if err != nil { p.log.Error("Connection failed. Skipping:", err) hostnames = append(hostnames[:r], hostnames[r+1:]...) continue } u[r] = struct{}{} c++ if c >= limit { break } } } // Check existing connections periodically and keep the number at maximum go p.checkConnections() return p, nil }