jbpm 中 ProcessEventListener 顺序问题

在 jBPM 商业流程中有一个 ProcessEventListener ,可以用来回调流程的执行过程,但是这个 Listener 的执行顺序非常奇怪。

首先我们先看看这个 interface

public interface ProcessEventListener {

  void beforeProcessStarted( ProcessStartedEvent event );
  void afterProcessStarted( ProcessStartedEvent event );
  void beforeProcessCompleted( ProcessCompletedEvent event );
  void afterProcessCompleted( ProcessCompletedEvent event );
  void beforeNodeTriggered( ProcessNodeTriggeredEvent event );
  void afterNodeTriggered( ProcessNodeTriggeredEvent event );
  void beforeNodeLeft( ProcessNodeLeftEvent event );
  void afterNodeLeft( ProcessNodeLeftEvent event );
  void beforeVariableChanged(ProcessVariableChangedEvent event);
  void afterVariableChanged(ProcessVariableChangedEvent event);


我相信大多数人看到这些方法回调大致可以猜测 afterProcessStarted 应该是在流程开始之后被调用,然而实际的调用顺序是这样的:

- beforeProcessStarted
  - beforeNodeTriggered
    - beforeNodeLeft
      - beforeNodeTriggered
        - beforeVariableChanged
        - beforeNodeLeft
          - beforeNodeTriggered
            - beforeNodeLeft
              - beforeNodeTriggered
            - beforeNodeLeft

afterProcessStarted 会在流程结束时被调用。有人提过 bug 但是官方认为这是程序设计,所以使用文档的形式 将这种方式说明了。

查看源代码可以在 RuleExecutor 中可以看到:

jbpm listener



jbpm process


- DefaultRuleContainer beforeVariableChanged ==>[ProcessVariableChanged(id=age; instanceId=age; oldValue=null; newValue=18; processName=BPTest; processId=FlowTest.BPTest)]
- DefaultRuleContainer afterVariableChanged ==>[ProcessVariableChanged(id=age; instanceId=age; oldValue=null; newValue=18; processName=BPTest; processId=FlowTest.BPTest)]
- DefaultRuleContainer beforeProcessStarted ==>[ProcessStarted(name=BPTest; id=FlowTest.BPTest)]
- event ==>[ProcessStarted(name=BPTest; id=FlowTest.BPTest)]
- DefaultRuleContainer beforeNodeTriggered ==>[ProcessNodeTriggered(nodeId=4; id=0; nodeName=StartPoint; processName=BPTest; processId=FlowTest.BPTest)]
- DefaultRuleContainer beforeNodeLeft ==>[ProcessNodeLeft(nodeId=4; id=0; nodeName=StartPoint; processName=BPTest; processId=FlowTest.BPTest)]
- DefaultRuleContainer beforeNodeTriggered ==>[ProcessNodeTriggered(nodeId=7; id=1; nodeName= 年龄是否大于 18; processName=BPTest; processId=FlowTest.BPTest)]
- DefaultRuleContainer beforeNodeLeft ==>[ProcessNodeLeft(nodeId=7; id=1; nodeName= 年龄是否大于 18; processName=BPTest; processId=FlowTest.BPTest)]
- DefaultRuleContainer beforeNodeTriggered ==>[ProcessNodeTriggered(nodeId=2; id=2; nodeName=A1Task; processName=BPTest; processId=FlowTest.BPTest)]
- DefaultRuleContainer beforeNodeLeft ==>[ProcessNodeLeft(nodeId=2; id=2; nodeName=A1Task; processName=BPTest; processId=FlowTest.BPTest)]
- DefaultRuleContainer beforeNodeTriggered ==>[ProcessNodeTriggered(nodeId=6; id=3; nodeName=A2Task; processName=BPTest; processId=FlowTest.BPTest)]
- DefaultRuleContainer beforeNodeLeft ==>[ProcessNodeLeft(nodeId=6; id=3; nodeName=A2Task; processName=BPTest; processId=FlowTest.BPTest)]
- DefaultRuleContainer beforeNodeTriggered ==>[ProcessNodeTriggered(nodeId=3; id=4; nodeName=End; processName=BPTest; processId=FlowTest.BPTest)]
- DefaultRuleContainer beforeNodeLeft ==>[ProcessNodeLeft(nodeId=3; id=4; nodeName=End; processName=BPTest; processId=FlowTest.BPTest)]
- DefaultRuleContainer beforeProcessCompleted ==>[ProcessCompleted(name=BPTest; id=FlowTest.BPTest)]
- DefaultRuleContainer afterProcessCompleted ==>[ProcessCompleted(name=BPTest; id=FlowTest.BPTest)]
- event ==>[ProcessCompleted(name=BPTest; id=FlowTest.BPTest)]
- DefaultRuleContainer afterNodeLeft ==>[ProcessNodeLeft(nodeId=3; id=4; nodeName=End; processName=BPTest; processId=FlowTest.BPTest)]
- DefaultRuleContainer afterNodeTriggered ==>[ProcessNodeTriggered(nodeId=3; id=4; nodeName=End; processName=BPTest; processId=FlowTest.BPTest)]
- DefaultRuleContainer afterNodeLeft ==>[ProcessNodeLeft(nodeId=6; id=3; nodeName=A2Task; processName=BPTest; processId=FlowTest.BPTest)]
- DefaultRuleContainer afterNodeTriggered ==>[ProcessNodeTriggered(nodeId=6; id=3; nodeName=A2Task; processName=BPTest; processId=FlowTest.BPTest)]
- DefaultRuleContainer afterNodeLeft ==>[ProcessNodeLeft(nodeId=2; id=2; nodeName=A1Task; processName=BPTest; processId=FlowTest.BPTest)]
- DefaultRuleContainer afterNodeTriggered ==>[ProcessNodeTriggered(nodeId=2; id=2; nodeName=A1Task; processName=BPTest; processId=FlowTest.BPTest)]
- DefaultRuleContainer afterNodeLeft ==>[ProcessNodeLeft(nodeId=7; id=1; nodeName= 年龄是否大于 18; processName=BPTest; processId=FlowTest.BPTest)]
- DefaultRuleContainer afterNodeTriggered ==>[ProcessNodeTriggered(nodeId=7; id=1; nodeName= 年龄是否大于 18; processName=BPTest; processId=FlowTest.BPTest)]
- DefaultRuleContainer afterNodeLeft ==>[ProcessNodeLeft(nodeId=4; id=0; nodeName=StartPoint; processName=BPTest; processId=FlowTest.BPTest)]
- DefaultRuleContainer afterNodeTriggered ==>[ProcessNodeTriggered(nodeId=4; id=0; nodeName=StartPoint; processName=BPTest; processId=FlowTest.BPTest)]
- DefaultRuleContainer afterProcessStarted ==>[ProcessStarted(name=BPTest; id=FlowTest.BPTest)]


2019-05-23 jbpm , drools , business-process , rule , rule-engine

drools workbench

Drools 是一个 Java 的商业过程实现,这是 Bob McWhirter 所编写的一个开源项目,由 JBoss 和 Red Hat Inc 支持。 Drools 提供一个核心的 Business Rules Engine(BRE) 和一个网页编写规则的管理系统(Drools Workbench)和 一个 Eclipse IDE 的插件,一同构成完整的 Drools 生态。

而这篇文章则主要侧重于 Drools Workbench。



The workbench stores its data, by default in the directory $WORKING_DIRECTORY/.niogit, for example wildfly-8.0.0.Final/bin/.niogit, but it can be overridden with the system property -Dorg.uberfire.nio.git.dir.

Note In production, make sure to back up the workbench data directory.

18.1.3. System properties Here’s a list of all system properties:

org.uberfire.nio.git.dir: Location of the directory .niogit. Default: working directory

org.uberfire.nio.git.daemon.enabled: Enables/disables git daemon. Default: true

org.uberfire.nio.git.daemon.host: If git daemon enabled, uses this property as local host identifier. Default: localhost

org.uberfire.nio.git.daemon.port: If git daemon enabled, uses this property as port number. Default: 9418

org.uberfire.nio.git.ssh.enabled: Enables/disables ssh daemon. Default: true

org.uberfire.nio.git.ssh.host: If ssh daemon enabled, uses this property as local host identifier. Default: localhost

org.uberfire.nio.git.ssh.port: If ssh daemon enabled, uses this property as port number. Default: 8001

org.uberfire.nio.git.ssh.cert.dir: Location of the directory .security where local certificates will be stored. Default: working directory

org.uberfire.nio.git.ssh.passphrase: Passphrase to access your Operating Systems public keystore when cloning git repositories with scp style URLs; e.g. git@github.com:user/repository.git.

org.uberfire.metadata.index.dir: Place where Lucene .index folder will be stored. Default: working directory

org.uberfire.cluster.id: Name of the helix cluster, for example: kie-cluster

org.uberfire.cluster.zk: Connection string to zookeeper. This is of the form host1:port1,host2:port2,host3:port3, for example: localhost:2188

org.uberfire.cluster.local.id: Unique id of the helix cluster node, note that ‘:’ is replaced with ‘_’, for example: node1_12345

org.uberfire.cluster.vfs.lock: Name of the resource defined on helix cluster, for example: kie-vfs

org.uberfire.cluster.autostart: Delays VFS clustering until the application is fully initialized to avoid conflicts when all cluster members create local clones. Default: false

org.uberfire.sys.repo.monitor.disabled: Disable configuration monitor (do not disable unless you know what you’re doing). Default: false

org.uberfire.secure.key: Secret password used by password encryption. Default: org.uberfire.admin

org.uberfire.secure.alg: Crypto algorithm used by password encryption. Default: PBEWithMD5AndDES

org.uberfire.domain: security-domain name used by uberfire. Default: ApplicationRealm

org.guvnor.m2repo.dir: Place where Maven repository folder will be stored. Default: working-directory/repositories/kie

org.guvnor.project.gav.check.disabled: Disable GAV checks. Default: false

org.kie.example.repositories: Folder from where demo repositories will be cloned. The demo repositories need to have been obtained and placed in this folder. Demo repositories can be obtained from the kie-wb-6.2.0-SNAPSHOT-example-repositories.zip artifact. This System Property takes precedence over org.kie.demo and org.kie.example. Default: Not used.

org.kie.demo: Enables external clone of a demo application from GitHub. This System Property takes precedence over org.kie.example. Default: true

org.kie.example: Enables example structure composed by Repository, Organization Unit and Project. Default: false

org.kie.build.disable-project-explorer: Disable automatic build of selected Project in Project Explorer. Default: false

To change one of these system properties in a WildFly or JBoss EAP cluster:

Edit the file $JBOSS_HOME/domain/configuration/host.xml.

Locate the XML elements server that belong to the main-server-group and add a system property, for example:


2019-05-21 drools , rule-engine

Entware-ng 使用

Entware-ng 是一个适用于嵌入式系统的软件包库,使用 opkg 包管理系统进行管理。之前的路由器刷了 Openwrt 之后直接能用命令行安装相关命令,之后的路由器,NAS 也能安装 Entware-ng 。可以将 Entware-ng 想象成嵌入式设备的一个包管理软件,能方便的用来在嵌入式设备上安装软件,现在在官方的源上已经有超过 2000 个软件包。





在 QNAP 上安装


和普通 Linux 下的包管理一样,只要输入命令就能够联网下载相关软件。

opkg update
opkg install git

所有软件包列表可以查看 http://pkg.entware.net/binaries/armv7/Packages.html

通过 opkg 安装的软件启动脚本在 /opt/etc/init.d/ 目录

单个启动命令 /opt/etc/init.d/software_name start

2019-05-19 entware-ng , package , linux , openwrt , merlin , 路由器

每天学习一个命令:pidstat 查看进程消耗资源

pidstat 是 sysstat 工具包含的一个命令,主要用于监控 Linux Kernel 管理的进程资源占用情况,包括 CPU,IO,内存,线程等等。

The pidstat command is used for monitoring individual tasks currently being managed by the Linux kernel.

pidstat 首次运行会显示系统自开机起各项统计,之后运行将显示从上一次运行到该次运行的统计信息。


apt-get install sysstat


pidstat [options] [interval] [times]


  • -u 默认参数,显示各个进程的 CPU 统计信息
  • -r 显示各个进程的内存使用情况
  • -d 显示各个进程的 IO 使用
  • -w 显示各个进程的上下文切换
  • -p PID 指定 PID

比如常见的每一秒查看 IO 统计,统计 10 次

pidstat -d 1 10


所有进程的 CPU 统计信息

直接运行 pidstat 默认显示所有进程的 CPU 使用信息,等效于 pidstat -u -p ALL

pidstat -u 1 10

Result fields:

  • UID
  • PID
  • %usr: 进程在用户空间占用 cpu 的百分比
  • %system: 进程在内核空间占用 CPU 百分比
  • %guest: 进程在虚拟机占用 CPU 百分比
  • %wait: 进程等待运行的百分比
  • %CPU: 进程占用 CPU 百分比
  • CPU: 处理进程的 CPU 编号
  • Command: 进程名


Following command will display PID memory usage 10 times every 2 seconds:

pidstat -r 2 10

Result fields:

  • UID
  • PID
  • Minflt/s : 每秒次缺页错误次数 (minor page faults),虚拟内存地址映射成物理内存地址产生的 page fault 次数
  • Majflt/s : 每秒主缺页错误次数 (major page faults), 虚拟内存地址映射成物理内存地址时,相应 page 在 swap 中
  • VSZ virtual memory usage : 该进程使用的虚拟内存 KB 单位
  • RSS : 该进程使用的物理内存 KB 单位
  • %MEM : 内存使用率
  • Command : 该进程的命令 task name

显示 IO 统计信息

pidstat -d

Result field:

  • UID
  • PID
  • kB_rd/s: 每秒进程从磁盘读取的数据量 KB 单位 read from disk each second KB
  • kB_wr/s: 每秒进程向磁盘写的数据量 KB 单位 write to disk each second KB
  • kB_ccwr/s: 每秒进程向磁盘写入,但是被取消的数据量,This may occur when the task truncates some dirty pagecache.
  • iodelay: Block I/O delay, measured in clock ticks
  • Command: 进程名 task name

T 选项来打印更详细信息

使用 -T [TASK|CHILD|ALL] 来报告打印更详细的信息,默认 pidstat 使用 TASK,表示监控独立的任务信息。

  • TASK 报告独立的进程
  • CHILD 报告进程下所有线程的情况
  • ALL 输出进程及线程统计信息

Specific PID

To show CPU, memory, IO:

pidstat -u -p PID
pidstat -r -p PID
pidstat -d -p PID

比如要查看 PID 为 12002 的进程的 CPU 使用情况,并且要查看所有子线程,每隔 1 秒输出一次,输出 10 次,则可以

pidstat -T ALL -u -p 12002 1 10


2019-05-14 linux , commmand , network , pidstat , iotop , ram , cpu

每天学习一个命令:pidof 查找进程 PID

pidof finds the process id’s(pids) of the names programs.


pidof [name]


find chrome pid

pidof chrome
pidof -s chrome


  • -s instructs the program to only return one pid.


  • pgrep

2019-05-14 pid , netstat , command , linux

Cross-platform Softwares I am using

This post will only list cross-platform softwares I used now. Each software has its own behaviors, and binded with its own shortcut. It takes time to be familiar with it. So I decided to use only cross-platform softwares in daily life in case I have to swith my main System. But it seems fine till now. I am happy with these great softwares.

IntelliJ IDEA

DescriptionIntelliJ IDEA is a Java integrated development environment for developing computer software. It is developed by JetBrains, and is available as an Apache 2 Licensed community edition, and in a proprietary commercial edition. Both can be used for commercial development.

Open Sources Alternatives:

  • Eclipse


DescriptionGoogle Chrome is a cross-platform web browser developed by Google. It was first released in 2008 for Microsoft Windows, and was later ported to Linux, macOS, iOS, and Android. The browser is also the main component of Chrome OS, where it serves as the platform for web apps.


  • vivaldi


SmartGit is a Git GUI client with support for SVN, GitHub, BitBucket pull requests and comments.


WizNote for Windows/Mac/Linux is a cross-platform cloud based note-taking client.


GoldenDict is an open-source dictionary program that gives translations of words and phrases for different languages. It allows the use of several popular dictionary file formats simultaneously and without conversion. The project aims to create a feature-rich dictionary search program.


[[TeamViewer]] is proprietary software for remote control, desktop sharing, online meetings, web conferencing and file transfer between computers.


pCloud is the secure cloud storage, where you can store, share and work on all your files.


VeraCrypt is a source-available freeware utility used for on-the-fly encryption. It can create a virtual encrypted disk within a file or encrypt a partition or the entire storage device with pre-boot authentication. VeraCrypt is a fork of the discontinued TrueCrypt project.


TagSpaces is an open-source data manager and file navigator. It helps organize files on local drives by adding tags to files. Users get the same user interface to manage their files on different platforms. TagSpaces is compatible with Windows, Linux, Mac, Android, iPhone, Firefox and Chrome.


Calibre is a cross-platform open-source suite of e-book software. Calibre supports organizing existing e-books into virtual libraries, displaying, editing, creating and converting e-books, as well as syncing e-books with a variety of e-readers. Editing books is supported for EPUB and AZW3 formats.


Telegram is a cloud-based instant messaging and voice over IP service developed by Telegram Messenger LLP, a privately held company registered in London, United Kingdom, founded by the Russian entrepreneur Pavel Durov and his brother Nikolai.


[[balenaEtcher]] is a powerful OS image flasher built with web technologies to ensure flashing an SDCard or USB drive is a pleasant and safe experience.

2019-05-10 applications , apps

使用 Stylus 扩展自定义页面样式

有油猴脚本可以用来修改网页页面,那么相应的也能通过挂载自己的定义的 CSS 来实现对页面的修改。




CSS 样式



  • https://userstyles.org/styles/119240/inoreader-countrystyle-flat-ui-remove-ads


2019-05-08 stylus , css , chrome , firefox , extension

Ruby 国内镜像

Update ruby

gem update --system
gem -v
gem sources --add https://gems.ruby-china.com/ --remove https://rubygems.org/
gem sources -l

确保只有 gems.ruby-china.com


bundle config mirror.https://rubygems.org https://gems.ruby-china.com
bundle install


2019-05-02 ruby , source , bundler , jekyll

威联通折腾篇十五:rtorrent-Pro 使用

QNAP CLUB 中淘到很多不错的应用,rtorrent-Pro 就是一款,现在作者升级了 rtorrent-pro 付费 15 欧元。这又是一款 BT 下载工具,界面非常美观。

rtorrent development for QNAP was started in 2008. Today after 10yrs from its 1st build, we provide you best Torrent app ever. rtorrent is an high performance and extra featured bittorrent client combined with simple and elegant user interface. rtorrent differentiates itself from other implementations by transferring data directly between file pages mapped to memory by the mmap() function and the network stack. On high-bandwidth connections, it claims to be able to seed at 3 times the speed of the official client. We strive to make rtorrent the best torrent client you could ever want!

rtorrent ui

支持的 QNAP 型号

  • armv7l - ARM processors: TS-x28/x31P/x31P2/x41 and more…
  • x86_64 - Intel/AMD64 CPU: TS-x51 and all higher (x53/61/63/70/71/73/77/78/80/82/88…)

如果不确定自己的 QNAP 型号,登录后台运行 uname -m 输出 CPU 架构如果是上面提到的两个就是支持的。


安装非常简单,下载应用,在后台上传安装即可。安装后默认的用户名是:rtorrent 密码是:admin.

rtorrent pro splash screen


/etc/init.d/rtorrent.sh [start|stop|restart]

Things to do





vi /share/CACHEDEV1_DATA/.qpkg/rtorrent/etc/rtorrent.conf

需要注意的是如果之前安装过其他 BT 下载工具,比如 Transmission 之类,可能会造成端口冲突 (DHT 端口),需要手工调整一下端口设置。

rtorrent 用到的端口:

  • 6881 DHT, 可在配置文件修改
  • 42000 连入端口
  • 19000

Change Paths

注意到该路径,rtorrent 相关的内容都安装在了该路径中。安装完毕之后 rtorrent 会在 Download 目录下创建名为 rtorrent 的文件夹,并且创建软链接 /share/Rdownload,rtorrent 下载的内容都会在该目录中。

In stock QNAP applications, a default Download share is used to save downloaded data from the Internet. Download share location is always static and only on the first initiated disk volume. In the default configuration, Rtorrent also uses the Download network share.

可以自定义 Rtorrent 存储的路径,创建共享文件夹名为 Rdownload,指定一块硬盘,当创建共享文件夹时,记得关闭 Rtorrent-Pro,创建成功后再启动。这样 rtorrent-Pro 就会使用新的路径。

Watch 监控目录

Transmission 之前的文章 也提到过监控某个文件夹,一旦有文件新加进去自动下载。

rtorrent 同样可以实现,默认的配置已经有配置,如果想要更加详细的了解,可以参考这里

Schedule 的语法:

# Schedule syntax: id,start,interval,command call cmd every interval seconds


schedule = watch_directory_1,20,10,"load.start=/downloads/watched/*.torrent"


用简短的一句话来总结上面的配置含义就是,定义了一个定时器,名叫 watch_directory_1, rTorrent 启动后 20 秒开始,每隔 10 秒执行一次命令,这个命令是从给定的目录中加载 torrent 文件。

  • schedule 的语法用逗号分隔四段,分别是 ID,启动,间隔时间,执行的命令
  • id 可以自行定义
  • start,rTorrent 启动后多久开始执行
  • interval ,间隔多长时间执行,如果是 0 则表示执行一次
  • load.start 表示从给定的目录(该目录必须要存在)加载 torrent 文件,这个地方除了 load.start 还可以用
    • load.start_verbose = file
    • load.verbose = file, verbose 会在终端将任何错误打印出来
    • load.normal

rtorrent 配置说明

# Maximum and minimum number of peers to connect to per torrent.
# throttle.min_peers.normal.set = 40
# throttle.max_peers.normal.set = 100
# 最小允许的 peer
min_peers = 40
# 最大允许 peer
max_peers = 100

# Same as above but for seeding completed torrents (-1 = same as downloading)
# throttle.min_peers.seed.set = 25
# throttle.max_peers.seed.set = 60
min_peers_seed = 10
max_peers_seed = 50

# Maximum number of simultanious uploads per torrent.
# throttle.max_uploads.set = 30
# 最大同时上传数
max_uploads = 10

# Global upload and download rate in KiB. "0" for unlimited.
# throttle.global_up.max_rate.set_kb = 0
# throttle.global_down.max_rate.set_kb = 0
# 最大下载速度
download_rate = 1024
# 最大上传速度
upload_rate = 512

# tracker_numwant = -1
#trackers.numwant.set = -1

# Max mapped memory
# nb does not refer to physical memory
# max_memory_usage = 768M
pieces.memory.max.set = 1024M

# Max number of files to keep open simultaneously
# max_open_files = 65536
#network.max_open_files.set = 1024

# max_open_http = 48
#network.http.max_open.set = 48

# Default directory to save the downloaded torrents.
# directory.default.set = /share/Rdownload/downloads/
# 下载目录
directory = /share/Rdownload/downloads/

# Default session directory. Make sure you don't run multiple instance
# of rtorrent using the same session directory. Perhaps using a
# relative path?
# session.path.set = /share/Rdownload/session
# 下载历史,包括进度信息,DHT 节点缓存
session = /share/Rdownload/session

# Schedule syntax: id,start,interval,command call cmd every interval seconds,
#                  starting from start.
# An interval of zero calls the task once while a start of zero calls it immediately.
# Start and interval may optionally use a time format dd:hh:mm:ss
# e.g. to start a task every day at 18:00, use 18:00:00,24:00:00.
# Commands: stop_untied =, close_untied =, remove_untied =
# Stop, Close or Remove the torrents that are tied to filenames that have been deleted

# Watch a directory for new torrents, and stop those that have been
# deleted.
# 将 torrent 文件放到该目录自动下载
schedule = watch_directory,10,10,load_start=/share/Rdownload/watch/*.torrent
# 将 torrent 文件移走停止下载
#schedule = untied_directory,10,10,stop_untied=

# Close torrents when diskspace is low.
# 当硬盘空间不足停止所有下载
schedule = low_diskspace,5,60,close_low_diskspace=1000M

# Stop torrents when reaching upload ratio in percent, when also reaching
# total upload in bytes, or when reaching final upload ratio in percent
# Example: stop at ratio 2.0 with at least 200 MB uploaded, or else ratio 20.0
# 在总上传量达到 200M 的情况下上传 / 下载率达到 200%,
# 或者在总上传量不足 200M 情况下上传 / 下载率达到 2000%, 则停止上传
#schedule = ratio,60,60,stop_on_ratio=200,200M,2000
#method.set = group.seeding.ratio.command, d.close=

# Port range to use for listening.
# network.port_range.set = 6890-6999
# bt 监听端口
port_range = 42000-42000

# Start opening ports at a random position within the port range.
# network.port_random.set = no
# 是否随机从上面的端口中选择
port_random = no

# Check hash for finished torrents. Might be usefull until the bug is
# fixed that causes lack of diskspace not to be properly reported.
# pieces.hash.on_completion.set = yes
check_hash = yes

# Set whether the client should try to connect to UDP trackers.
# use_udp_trackers = yes
trackers.use_udp.set = yes

# Alternative calls to bind and ip that should handle dynamic ip's.
#schedule = ip_tick,0,1800,ip=rakshasa
#schedule = bind_tick,0,1800,bind=rakshasa

# Remove a scheduled event
# schedule_remove = "ip_tick"

# Enable DHT support for trackerless torrents or when all trackers are down.
# May be set to "disable" (completely disable DHT), "off" (do not start DHT),
# "auto" (start and stop DHT as needed), or "on" (start DHT immediately).
# The default is "off". For DHT to work, a session directory must be defined.
# dht.mode.set = auto
dht = auto

# UDP port to use for DHT.
# DHT 的 UDP 端口
# dht_port = 6881
dht.port.set = 6882

# Enable peer exchange (for torrents not marked private)
# protocol.pex.set = yes
protocol.pex.set = yes
#peer_exchange = yes

# network.scgi.open_port =
scgi_port =
#scgi_local = /var/run/rtorrent-rpc.socket

network.xmlrpc.dialect.set = i8
encoding_list = UTF-8



BT 下载的工具有很多,qBittorrent,Transmission,rtorrent, uTorrent,等等,非常多,wiki 有一张非常详细的对比图,在不同系统上都有着各自的最佳选择。对占用资源,下载效率的测试还没有来得及验证,等使用一段时间后再来更新吧。

Android Client

记得启用之后可以使用 [[Transdroid]] Android 客户端来管理 rtorrent-pro. 可以从 Google Play Store 下载,或者从官网:

安装之后在设置中添加 Server,名字,服务器类型,IP,HOST NAME,User name, password 没啥好说,这里的用户名和密码和界面上的用户名和密码一致。

在高级设置中,记得将 Port Number 设置为 6009, 或者使用 Use SSL 的话,输入 6008.



2019-05-02 qnap , nas , bt , pt

威联通折腾篇十三:替换默认 shell 为 zsh

默认 SSH 登录到 QNAP 的 login shell 可以通过 echo $SHELL 来查看到是


默认的这个 bash 是 QNAP 自带的

/bin/sh --version
GNU bash, version 3.2.57(1)-release (x86_64-QNAP-linux-gnu)
Copyright (C) 2007 Free Software Foundation, Inc.

也是一个相对比较简陋的版本,自动补全很难用,也没有语法高亮。所以想能不能把 QNAP 自带的 shell 换成日常使用的 ZSH,QNAP 本质上就是一个 Linux,所以理所当然的应该是可行的。


首先要要解决的问题是安装问题,普通的 Linux 发行版直接使用一行命令就可以完成,QNAP 可以使用 QNAP club 别人提供的版本,直接安装即可

wget https://cdn.qnapclub.eu/qpkg_artifacts/ZSH_5.7.0_x86_64/ZSH_5.7.0_x86_64.qpkg
sh ZSH_5.7.0_x86_64.qpkg

如果你参考过我之前的文章 你应该知道添加了 QNAP Club 的地址可以直接在 App Center 中直接搜索下载。

安装好之后,默认的 zsh 会安装到



SSH 登陆 QNAP 之后直接在终端输入 zsh 即可进入 zsh。

ZSH 一些强大的功能:

  • 强大的补全功能
  • 错误检查以及自动更正
  • 命令别名、路径别名
  • 强大的提示信息

默认的配置在 /opt/ZSH 中,可以自己做一些微调,比如

vi /opt/ZSH/zshrc.zsh-template
vi /root/.zshrc





如果在使用过程中发现,delete功能异常,比如delete虽然删除了字符但是向右多显示一个空格,而且不显示移动光标 那么可以编辑zsh配置文件

vi ~/.zshrc



保存, 然后执行, 使配置生效

source ~/.zshrc

2019-05-01 qnap , qnap-tutorial , qpkg , linux , shell , login-shell , zsh , oh-my-zsh , bash




  • 使用 Quartz 发布 Obsidian 笔记库 自从使用 [[Obsidian]] 以来就一直想要有一个开源版本的 [[Obsidian Publish]] 代替,过去这几年也尝试了不少方案,比如 Jekyll 静态网站生成,比如使用 [[Logseq]] 生成网站, 然后还想过从 Obsidian 同步到 Notion 里面,然后再使用 [[NotionNext]] 来生成网站。
  • 爱沙尼亚电子居民申请记录 在网上逛论坛的时候,偶然看到有人提到了一个爱沙尼亚电子公民的电子居民卡,看起来挺有意思的,之前就看到过 [[帕劳数字居民身份证]],去检索了一下发现帕劳已经涨价到了 248 欧元,爱沙尼亚电子公民感觉上类似,所以就简单的记录一下。
  • DNS 泄漏以及如何防止 什么是 DNS 泄漏
  • 从内地到香港出金最佳的方法 银行汇款
  • Homerow 使用 Vimium 的方式控制 macOS Homerow 是一个 macOS 上的快捷键助手,可以使用类似 [[vimium]] 的操作方式来控制 macOS。