把玩ebuddy(3)

早上起来刷微信, 觉得网页版微信的提示信息大可用ebuddy来响应. 说干就干,以下是解 决方案.

gnotifier

写作时,我的firefox版本是44.0.2, 需要安装gnotifier这个插件,从而把firefox的提示 消息转为系统提示信息, 下载地址在:

https://addons.mozilla.org/en-US/firefox/addon/gnotifier/

点击Add to Firefox即完成安装:

/images/2016_03_05_21_50_12_766x490.jpg

查看dbus消息

gnotifier将网页版微信的提示消息转为了系统提示消息, 那么只需要获取到系统消息总 线里的提示信息, 筛选出我们要的类型后, 给ebuddy发送相应的指令即可.

dbus-monitor工具可用于侦听dbus总线里的消息, 我们来运行一下,如下:

$  dbus-monitor --session
interface='org.freedesktop.Notifications',member='Notify'

signal time=1457186062.137082 sender=org.freedesktop.DBus ->
destination=:1.163 serial=2 path=/org/freedesktop/DBus;
interface=org.freedesktop.DBus; member=NameAcquired
   string ":1.163"
signal time=1457186062.137154 sender=org.freedesktop.DBus ->
destination=:1.163 serial=4 path=/org/freedesktop/DBus;
interface=org.freedesktop.DBus; member=NameLost
   string ":1.163"
method call time=1457186083.405690 sender=:1.39 -> destination=:1.14
serial=220 path=/org/freedesktop/Notifications;
interface=org.freedesktop.Notifications; member=Notify
   string "Firefox"
   uint32 0
   string "/tmp/gnotifier-3Fh5Sa"
   string "yfp"
   string "[Sticker][Sticker][Sticker]"
   array [
   ]
   array [
   ]
   int32 -1
method call time=1457186086.866000 sender=:1.39 -> destination=:1.14
serial=221 path=/org/freedesktop/Notifications;
interface=org.freedesktop.Notifications; member=Notify
   string "Firefox"
   uint32 0
   string "/tmp/gnotifier-9kaLsI"
   string "yfp"
   string "test"
   array [
   ]
   array [
   ]
   int32 -1

以上是两条从微信号为yfp的用户发送给网页端微信的dbus总线消息, 我们要注意的是, 需要从dbus session总线取得此信息(system bus和session bus的差别可以自行Google).

python2-dbus

ArchLinux下有python-dbuspython2-dbus两个关于dbus的python绑定库, 个人比较 习惯python2的缘故,安装python2-dbus

$ sudo pacman -Ss python2-dbus
extra/python2-dbus 1.2.0-5 [installed]
    Python 2.7 bindings for DBUS

用于过滤/提取dbus总线消息的python代码如下, 另存为DbusEbuddy.py:

import glib
import dbus
import subprocess
from dbus.mainloop.glib import DBusGMainLoop

def notifications(bus, message):
    if (len(message.get_args_list()) > 0):
        if ('Firefox' == message.get_args_list()[0]):
                if ('yfp' == message.get_args_list()[3]):
                    bashCommand = 'echo 01 > /dev/udp/127.0.0.1/8888'
                    output = subprocess.check_output(['bash','-c',bashCommand])

DBusGMainLoop(set_as_default=True)

bus = dbus.SessionBus()
bus.add_match_string_non_blocking("eavesdrop=true,\
    interface='org.freedesktop.Notifications', member='Notify'")
bus.add_message_filter(notifications)

mainloop = glib.MainLoop()
mainloop.run()

简单解释一下, 这几行代码首先attach到dbus的sessionbus总线, org.freedesktop.Notification端口上所有Notify的成员, 如果匹配到这种消息, 则 通过add_message_filter()调用回调函数.

notifications是我们定义的回调函数,这个回调函数同样很简单, 如果消息长度大于 0(消息非空), 则检查消息的来源(message.get_args_list()[0]), 选取来自Firefox的 , 由yfp(messages.get_args_list()[3])用户发来的消息, 作出对应的动作 (echo 01 > /dev/udp/127.0.0.1/8888).

使用

首先开启pybuddyDX库(注意要先安装python2版本的pyusb, 上一篇文章有讲):

$ git clone git@github.com:purplepalmdash/pybuddy-dx.git
$ sudo python2 ~/Code/python/pybuddy-dx/pybuddyDX.py

此时系统在8888端口监听ebuddy动作, 直接运行DbusEbuddy.py

$ sudo python2 ~/Code/python/DbusEbuddy.py

以后每条由用户yfp发来的消息,都将引发ebuddy人偶执行01指令对应的动作.

延伸

可以匹配不同的人名, 执行不同的动作. 例如:

李四	执行02指令
王五	执行12指令
某某群	执行08指令

当然,根据需要,也可以制定一些规则,譬如某VIP用户, 就是微信里你特别看重的那个人 ,TA发消息来以后, 人偶心跳不止(指令19即是). 但这样一来,就引入了清零问题, 即重置 人偶状态, 很简单,我们用notify-send这条命令, 发送出指令17给人偶让它重置状态 即可.

代码的修改:

def notifications(bus, message):
    if (len(message.get_args_list()) > 0):
        if ('Firefox' == message.get_args_list()[0]):
                if ('yfp' == message.get_args_list()[3]):
                    bashCommand = 'echo 19 > /dev/udp/127.0.0.1/8888'
                    output = subprocess.check_output(['bash','-c', bashCommand])
        if ('notify-send' == message.get_args_list()[0]):
                if ('Clear' == message.get_args_list()[3]):
                    bashCommand = 'echo 17 > /dev/udp/127.0.0.1/8888'
                    output = subprocess.check_output(['bash','-c', bashCommand])

而对应的清空命令则可以写成alias形式(我用的是zsh, bash类似):

$ vim ~/.zshrc
alias clearnotify="notify-send 'Clear' 'This is a clear ebuddy notification.' --icon=dialog-information"
$ source ~/.zshrc
$ clearnotify

测试

现在开始测试, 首先让yfp发微信给浏览器里登录的微信用户, 可以看到, 当浏览器收到 消息后, 系统桌面出现提示, 人偶心脏处的红灯开始狂闪, 不会停止.

/images/1039489558.jpg

输入clearnotify命令后, 人偶恢复正常.

下一步需要做的

  1. Windows响应?
  2. 如何通过微信的API获取到好友列表,从而动态指定需要监听的人和事件?
  3. 图形界面的配置?

把玩ebuddy(2)

ArchLinux配置过程

因为ArchLinux默认python版本为python3, 使用python2激活e-buddy人偶:

$ sudo pacman -S python2-pip
$ sudo pip2 install pyusb
$ git clone git@github.com:purplepalmdash/pybuddy-dx.git
$ sudo python2 ~/Code/ebuddy/pybuddy-dx/pybuddyDX.py
$ sudo netstat -anp | grep 8888
udp        0      0 127.0.0.1:8888          0.0.0.0:*                           14635/python2 

接下来就是往127.0.0.1:8888发送指令控制人偶的干活了。具体的指令可以见上一篇文章。

定期检查邮件控制人偶

先安装用于检查imap服务端状态的python模块:

$ sudo pip2 install imapclient

检查邮件的脚本如下, 该脚本检查163邮箱的IMAP服务器,如果有新邮件,人偶的头就会出现颜色渐 变,否则,则显示绿灯闪烁:

#!/usr/bin/env python
import imaplib 
from imapclient import IMAPClient
import time
import subprocess
import thread

DEBUG = True
 
HOSTNAME = 'imap.163.com'
USERNAME = 'XXXXXXXX'
PASSWORD = 'XXXXXXXX'
MAILBOX = 'Inbox'
newmails = 0
 
NEWMAIL_OFFSET = 0   # my unread messages never goes to zero, yours might
MAIL_CHECK_FREQ = 60 # check mail every 60 seconds

# Define a function for checking email
def check_mail( threadName):
    while True:
        # Login into the imap server and check the numbers for the new mail.
        server = IMAPClient(HOSTNAME, use_uid=True, ssl=True)
        server.login(USERNAME, PASSWORD)
        if DEBUG:
            print('Logging in as ' + USERNAME)
            select_info = server.select_folder(MAILBOX)
            print('%d messages in INBOX' % select_info['EXISTS'])

        folder_status = server.folder_status(MAILBOX, 'UNSEEN')
        global newmails
        newmails = int(folder_status['UNSEEN'])

        if DEBUG:
            print "You have", newmails, "new emails!"
        time.sleep(MAIL_CHECK_FREQ)

def loop():
 
    if newmails > NEWMAIL_OFFSET:
        bashCommand = 'echo 12 > /dev/udp/127.0.0.1/8888'
        output = subprocess.check_output(['bash','-c', bashCommand])
        time.sleep(8)
    else:
        bashCommand = 'echo 08 > /dev/udp/127.0.0.1/8888'
        output = subprocess.check_output(['bash','-c', bashCommand])
        time.sleep(5)
 
if __name__ == '__main__':
    try:
        print 'Press Ctrl-C to quit.'
        thread.start_new_thread( check_mail, ("Thread-1", ) )
        while True:
            loop()
    finally:
        print "finally comes here!"

conntrack-tools usage

参考

https://blogs.it.ox.ac.uk/networks/2014/09/30/linux-and-eduroam-nat-logging-perl-and-regular-expressions/

安装

ArchLinux下:

$ sudo pacman -S conntrack-tools

使用

记录新建/销毁连接数至文件:

$ sudo touch /var/log/conntrack-data.log
$ sudo chmod 777 /var/log/conntrack-data.log
$ sudo conntrack -E -eNEW,DESTROY --src-nat -otimestamp,extended --buffer-size=104857600 > /var/log/conntrack-data.log

e-buddy消息提醒服务设计思路(1)

设计目的

设计为一个系统通用的? 还是特定应用的?

监控 vs 告警

监控某项指标? 然后告警?

总线?

DBUS 总线?
D-Bus For Python.

把玩e-Buddy

状态

逆向工程得出的控制指令:

################
#Commands
################
# GLADNESS =        00
# FEAR =            01
# FIZZ =            02
# PLEASANTSURPRISE =03
# GRIEF =                       04
# FURY =                        05
# QUELL =                       06
# REDHEAD =             07
# GREENHEAD =           08
# BLUEHEAD =            09
# YELLOWHEAD =          10
# BLAME =                       11
# BLUEGREENHEAD =       12
# WHITEHEAD =           13
# HEART =                       14
# WINGS =                       15
# BODY =                        16
# NOEFFECT =            17
# ONLINE =                      18
# BUSY =                        19
# DAZE =                        20
# BACKSOON =            21
# AWAY =                        22
# PHONE =                       23
# LUNCH =                       24
# OFFLINE =             25

功能列表:

功能代码描述详细描述
00开心头灯变换彩色,翅膀扇动
01惊恐头灯变换彩色,心灯红色,翅膀扇动
02嘶嘶头灯变换彩色,心灯红色,翅膀扇动, 身体转动
03惊喜头灯变换彩色,心灯红色,翅膀扇动, 之后身体转动,头灯红
04酸溜溜头灯变换彩色,翅膀扇动, 之后头灯变幻
05愤怒头灯红色,翅膀扇动, 身体扭动
06扭动头灯蓝色,翅膀扇动, 身体平缓扭动
07红头头灯红色, 闪烁
08绿头头灯绿色,闪烁
09蓝头头灯蓝色,闪烁
10黄头头灯黄色,闪烁
11责骂头灯蓝色,闪烁
12绿色->蓝色头头灯绿色到蓝色变换
13白头闪头灯白色变换
14心跳心灯红色闪烁后,身体转动
15挥翅翅膀不停挥动
16身体转动身体转动
17无效果无任何效果
18在线心灯一直闪动,不会停止,除非转为其他效果
19忙碌心灯一直快速闪动,不会停止,除非转为其他效果
20发呆心灯一直慢速闪动,不会停止,除非转为其他效果
21马上回来心灯三短闪烁后停止一会,不会停止,除非转为其他效果
22离开心灯三短闪烁后停止一会,不会停止,除非转为其他效果
23离开心灯持续跳动,不会停止,除非转为其他效果
24离开心灯两短后持续跳动,不会停止,除非转为其他效果
25离开心灯四短后,永久沉默

e-buddy本地服务器

有人已经实现了e-buddy的python库,直接拷贝到本地并运行:

$ git clone git@github.com:purplepalmdash/pybuddy-dx.git
$ virtualenv2 venv2 --python=python2.7
 ✗ . ~/venv2/bin/activate
(venv2) ➜  _posts git:(master) ✗ python
Python 2.7.11 (default, Dec  6 2015, 15:43:46) 
[GCC 5.2.0] on linux2
$ pip install pyusb
$ python pybuddyDX1.py
2016-02-23 15:51:39,242 INFO     Searching e-buddy...
2016-02-23 15:51:39,399 INFO     DX e-buddy found!
2016-02-23 15:51:39,962 INFO     Starting daemon...

py文件运行后将监听127.0.0.1的8888端口,通过往该端口输入状态码,e-buddy将呈现不同的状态 。

操纵e-buddy

用python操控e-buddy的命令如下:

python
Python 2.7.11 (default, Dec  6 2015, 15:43:46) 
[GCC 5.2.0] on linux2
Type "help", "copyright", "credits" or "license" for more information.
>>> import socket
>>> UDP_IP = "127.0.0.1"
>>> UDP_PORT = 8888
>>> sock = socket.socket(socket.AF_INET,  socket.SOCK_DGRAM)
>>> sock.sendto("07",(UDP_IP, UDP_PORT))
2

或者,直接用bash来操作udp socket:

#!/bin/bash
while true
do
echo 07 > /dev/udp/127.0.0.1/8888
sleep 3
done

以上的脚本就可以直接将e-buddy的头像置为红色,且一直闪烁。