Esempio n. 1
0
func main() {
	go func() {
		// goto: http://localhost:6060/debug/pprof/ for goroutine info!
		fmt.Println(http.ListenAndServe("localhost:6060", nil))
	}()

	bcfg := babel.BotConfig{
		Nick:     "babelbot",
		RoomName: "test",
		Cmds: []plugin.CmdPluginDialer{
			plugin.CmdPluginDialer{
				Cmd:  "python",
				Args: []string{"log_everything.py"},
			},
		},
	}
	ws := &connection.WSConnectionDialer{
		UrlFormat: connection.EUPHORIA_URL_FORMAT,
	}

	ctx := scope.New()
	proto.SetLogger(ctx, logrus.StandardLogger())

	err := bcfg.Start(ctx, ws)
	if err != nil {
		proto.GetLogger(ctx).Errorf("bcfg.Start failure in main(): %s", err)
	}
}
Esempio n. 2
0
// Start is a non-blocking operation that starts listening for packets from outgoing
// and streaming packets to incoming.
func (c *WSConnection) start() {

	localIncoming := make(chan *hproto.Packet, 1)
	go c.receivePacket(localIncoming)
	go func() {
		for {
			select {
			// Send packet
			case msg := <-c.outgoing:
				if err := c.conn.WriteJSON(msg); err != nil {
					c.Kill(err)
				}
			// Dispatch packet
			case msg := <-localIncoming:
				c.incoming <- msg
				go c.receivePacket(localIncoming)
			// We're done
			case <-c.ctx.Done():
				return
			// Placeholder for debugging or monitoring code
			case <-time.After(time.Second * 30):
				proto.GetLogger(c.ctx).Debugf("WSConnection to %s still looping.", c.roomName)
			}
		}
	}()
}
Esempio n. 3
0
func (d *CmdPluginDialer) Dial(ctx scope.Context) (proto.Plugin, error) {
	cmdPlugin := &CmdPlugin{
		ctx:  ctx.Fork(),
		cmd:  d.Cmd,
		args: d.Args,
	}
	err := cmdPlugin.connect()
	if err != nil {
		proto.GetLogger(cmdPlugin.ctx).Errorf("Failed to connect CmdPlugin: %s", err)
		return nil, err
	}
	return cmdPlugin, nil
}
Esempio n. 4
0
func (p *RetryPlugin) ReceiveOut() (*proto.Packet, error) {
	p.lock.Lock()
	plugin := p.plugin
	p.lock.Unlock()
	packet, err := plugin.ReceiveOut()
	if err != nil {
		proto.GetLogger(p.ctx).Warningf("Error receiving out from retry-wrapped plugin: %s", err)
		startErr := p.start(plugin)
		if startErr != nil {
			return nil, startErr
		}
		return p.ReceiveOut()
	}
	return packet, nil
}
Esempio n. 5
0
func (p *RetryPlugin) Send(packet *proto.Packet) error {
	p.lock.Lock()
	plugin := p.plugin
	p.lock.Unlock()
	err := plugin.Send(packet)
	if err != nil {
		proto.GetLogger(p.ctx).Warningf("Error sending to retry-wrapped plugin: %s", err)
		startErr := p.start(plugin)
		if startErr != nil {
			return startErr
		}
		return plugin.Send(packet)
	}
	return nil
}
Esempio n. 6
0
func (c *RetryConnection) Receive() (*hproto.Packet, error) {
	c.lock.Lock()
	conn := c.conn
	c.lock.Unlock()
	packet, err := conn.Receive()
	if err != nil {
		proto.GetLogger(c.ctx).Infof("Error receiving from retry-wrapped connection: %s", err)
		startErr := c.start(conn)
		if startErr != nil {
			return nil, startErr
		}
		return c.Receive()
	}
	return packet, nil
}
Esempio n. 7
0
func (c *RetryConnection) Send(packet *hproto.Packet) error {
	c.lock.Lock()
	conn := c.conn
	c.lock.Unlock()
	err := conn.Send(packet)
	if err != nil {
		proto.GetLogger(c.ctx).Infof("Error sending to retry-wrapped connection: %s", err)
		startErr := c.start(conn)
		if startErr != nil {
			return startErr
		}
		return c.Send(packet)
	}
	return nil
}
Esempio n. 8
0
func (pg *CmdPlugin) listen() {
	proto.GetLogger(pg.ctx).Infof("CmdPlugin %s started", pg.Name())
	stdoutChan := make(chan *proto.Packet)
	// TODO: break this out into a separate function
	go func() {
		p, err := pg.readOut()
		if err != nil {
			pg.Kill(err)
			return
		}
		stdoutChan <- p
	}()

	stderrChan := make(chan error)
	// TODO: break this out into a separate function
	go func() {
		stderr, err := pg.readErr()
		if err != nil {
			pg.Kill(fmt.Errorf("Plugin error: %s", err))
			return
		}
		stderrChan <- stderr
	}()

	for {
		select {
		case p := <-stdoutChan:
			pg.stdoutChan <- p
			go func() {
				p, err := pg.readOut()
				if err != nil {
					pg.Kill(err)
					return
				}
				stdoutChan <- p
			}()
		case p := <-pg.stdinChan:
			if err := pg.writeIn(p); err != nil {
				pg.Kill(err)
				return
			}
		case <-pg.ctx.Done():
			return
		}
	}
}
Esempio n. 9
0
func (d *WSConnectionDialer) Dial(ctx scope.Context, roomName string) (proto.Connection, error) {
	ws := WSConnection{
		roomName: roomName,
		ctx:      ctx.Fork(),
		incoming: make(chan *hproto.Packet, 8),
		outgoing: make(chan *hproto.Packet, 8)}

	dialer := websocket.Dialer{
		HandshakeTimeout: 5 * time.Second,
	}
	url := fmt.Sprintf(d.UrlFormat, ws.roomName)
	proto.GetLogger(ws.ctx).Infof("Connecting to: %s", url)
	conn, _, err := dialer.Dial(url, nil)
	if err != nil {
		return nil, err
	}
	ws.conn = conn
	ws.start()
	return &ws, nil
}
Esempio n. 10
0
func (p *RetryPlugin) start(errorPlugin proto.Plugin) error {
	p.lock.Lock()
	defer p.lock.Unlock()

	if errorPlugin == p.plugin {
		for p.retries < 3 {
			p.retries++
			plugin, err := p.dialer.Dial(p.ctx)
			if err != nil {
				proto.GetLogger(p.ctx).Infof("Error dialing retry-wrapped plugin: %s", err)
				continue
			}
			p.plugin = plugin
			return nil
		}
		err := fmt.Errorf("Too many retries")
		p.Kill(err)
		return p.ctx.Err()
	}
	return nil
}
Esempio n. 11
0
func (c *RetryConnection) start(errorConn proto.Connection) error {
	c.lock.Lock()
	defer c.lock.Unlock()
	if errorConn == c.conn {
		for c.retries < 3 {
			// This retrying stuff needs a serious upgrade
			c.retries++
			conn, err := c.dialer.Dial(c.ctx, c.roomName)
			if err != nil {
				// Try again after logging the failure
				proto.GetLogger(c.ctx).Infof("Error connecting with retry-wrapped connection: %s", err)
				continue
			}
			c.conn = conn
			return nil
		}
		err := fmt.Errorf("Too many retries")
		c.Kill(err)
		return c.ctx.Err()
	}
	return nil
}
Esempio n. 12
0
func (b *Bot) Kill(err error) {
	if b.ctx.Alive() {
		proto.GetLogger(b.ctx).Errorf("Bot killed: %s", err)
		b.ctx.Terminate(err)
	}
}