Skip to content

Instantly share code, notes, and snippets.

@leapar
Created September 29, 2017 01:15
Show Gist options
  • Save leapar/0e5702dbffb791d46319a5e8c48446fc to your computer and use it in GitHub Desktop.
Save leapar/0e5702dbffb791d46319a5e8c48446fc to your computer and use it in GitHub Desktop.

hubot + bearychat

@leapar
Copy link
Author

leapar commented Sep 29, 2017

安装

参考http://www.jevic.cn/2017/02/07/chatops/

doc

hubot自带express,监听8080,可以用export EXPRESS_PORT 进行设置端口。
1

配置

修改example.coffee文件,响应http 请求
2

设置channel

创建一个channel,取一个名字,然后查看该channel的id
5

post消息

http://127.0.0.1:8080/hubot/chatsecrets/=bwKSN
{"text":"> 内存空间不足 \r\n >> 标签: \r\n >>> host=wang.pc.windows \r\n >> 表达式:\r\n >>> avg(system.cpu.idle) < 5 \r\n>> 当前值:\r\n >>> 1 "}

3

查看响应

4

@leapar
Copy link
Author

leapar commented Sep 29, 2017

hubot代码分析

hubot-script-shellcmd

https://github.com/coderofsalvation/hubot-script-shellcmd/blob/master/src/shellcmd.coffee
http://coffeescript.org/#nodejs-usage
// Description:
//   List/Execute shellcommands from a specified folder.

// Dependencies:
//  None

// Configuration
//   HUBOT_SHELLCMD="bash/handler" (cp the example 'bash'-directory to your root/runtime folder)

// where 'handler' is a shellscript like:

// Commands:
//  Hubot shellcmd - list (bash)shell commands 
//  Hubot shellcmd <foo> - performs bashshell command

// Author:
//  Leon van Kammen / Coderofsalvation

var fs;

fs = require("fs");

if (!process.env.HUBOT_SHELLCMD) {
  process.env.HUBOT_SHELLCMD = "bash/handler";
}

if (!fs.existsSync(process.env.HUBOT_SHELLCMD)) {
  console.log(process.env.HUBOT_SHELLCMD + " not found in hubot working dir..defaulting to example handler at " + __dirname + "/../bash/handler");
  process.env.HUBOT_SHELLCMD = __dirname + "/../bash/handler";
}

if (!process.env.HUBOT_SHELLCMD_KEYWORD) {
  process.env.HUBOT_SHELLCMD_KEYWORD = "shellcmd";
}

module.exports = function(robot) {
  var run_cmd;
  run_cmd = function(cmd, args, envs, cb) {
    var child, opts, spawn;
    console.log("spawn!");
    spawn = require("child_process").spawn;
    opts = {
      env: envs
    };
    child = spawn(cmd, args, opts);
    child.stdout.on("data", function(buffer) {
      return cb(buffer.toString());
    });
    return child.stderr.on("data", function(buffer) {
      return cb(buffer.toString());
    });
  };
  //child.stdout.on "end", -> cb resp
  robot.respond("/" + process.env.HUBOT_SHELLCMD_KEYWORD + "$/i", function(msg) {
    var cmd, envs, key, ref, value;
    cmd = process.env.HUBOT_SHELLCMD;
    envs = {};
    ref = msg.envelope.user;
    for (key in ref) {
      value = ref[key];
      envs["HUBOT_USER_" + key.toUpperCase()] = value;
    }
    return run_cmd(cmd, [], envs, function(text) {
      return msg.send(text);
    });
  });
  return robot.respond("/" + process.env.HUBOT_SHELLCMD_KEYWORD + " (.*)/i", function(msg) {
    var args, cmd, envs, key, ref, value;
    msg.match[0] = msg.match[0].replace(/^[a-z0-9]+$/i);
    msg.match.shift();
    args = msg.match[0].split(" ");
    cmd = process.env.HUBOT_SHELLCMD;
    envs = {};
    ref = msg.envelope.user;
    for (key in ref) {
      value = ref[key];
      envs["HUBOT_USER_" + key.toUpperCase()] = value;
    }
    return run_cmd(cmd, args, envs, function(text) {
      return msg.send(text.replace("\n", ""));
    });
  });
};

给hubot绑定两个规则:

  1. respond "/ shellcmd $/i"
  2. respond "/ shellcmd (.*)/i"

respond 绑定

  hear (regex, options, callback) {
    this.listeners.push(new Listener.TextListener(this, regex, options, callback))
  }

 respond (regex, options, callback) {
    this.hear(this.respondPattern(regex), options, callback)
  }

adapter 都会调用bot的receive函数

// Public: Dispatch a received message to the robot.
  //
  // Returns nothing.
  receive (message) {
    this.robot.receive(message)
  }
  receive (message, cb) {
    // When everything is finished (down the middleware stack and back up),
    // pass control back to the robot
    this.middleware.receive.execute({ response: new Response(this, message) }, this.processListeners.bind(this), cb)
  }

  // Private: Passes the given message to any interested Listeners.
  //
  // message - A Message instance. Listeners can flag this message as 'done' to
  //           prevent further execution.
  //
  // done - Optional callback that is called when message processing is complete
  //
  // Returns nothing.
  // Returns before executing callback
  processListeners (context, done) {
    // Try executing all registered Listeners in order of registration
    // and return after message is done being processed
    let anyListenersExecuted = false

    async.detectSeries(this.listeners, (listener, done) => {
      try {
        listener.call(context.response.message, this.middleware.listener, function (listenerExecuted) {
          anyListenersExecuted = anyListenersExecuted || listenerExecuted
          // Defer to the event loop at least after every listener so the
          // stack doesn't get too big
          process.nextTick(() =>
            // Stop processing when message.done == true
            done(context.response.message.done)
          )
        })
      } catch (err) {
        this.emit('error', err, new this.Response(this, context.response.message, []))
        // Continue to next listener when there is an error
        done(false)
      }
    },
    // Ignore the result ( == the listener that set message.done = true)
    _ => {
      // If no registered Listener matched the message

      if (!(context.response.message instanceof Message.CatchAllMessage) && !anyListenersExecuted) {
        this.logger.debug('No listeners executed; falling back to catch-all')
        this.receive(new Message.CatchAllMessage(context.response.message), done)
      } else {
        if (done != null) {
          process.nextTick(done)
        }
      }
    })
  }

最后当消息来,执行listeners里面的自定义处理函数。processListeners函数写的很有水平。

参考

  1. 理解 Node.js 里的 process.nextTick() http://www.oschina.net/translate/understanding-process-next-tick
  2. detectSeries(coll, iteratee, callbackopt) https://github.com/async-js/async#async.detectseries

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment