// File: /workspace/github_c_makefile_star2_O2/nilyang[P]redis-tdd-annotation/src/pubsub.c
// Function: pubsubPublishMessage
int pubsubPublishMessage(robj *channel, robj *message) {
    int receivers = 0;
    dictEntry *de;
    listNode *ln;
    listIter li;

    /* Send to clients listening for that channel */
    // 取出包含所有订阅频道 channel 的客户端的链表
    // 并将消息发送给它们
    de = dictFind(server.pubsub_channels,channel);
    if (de) {
        list *list = dictGetVal(de);
        listNode *ln;
        listIter li;

        // 遍历客户端链表，将 message 发送给它们
        listRewind(list,&li);
        while ((ln = listNext(&li)) != NULL) {
            redisClient *c = ln->value;

            // 回复客户端。
            // 示例：
            // 1) "message"
            // 2) "xxx"
            // 3) "hello"
            addReply(c,shared.mbulkhdr[3]);
            // "message" 字符串
            addReply(c,shared.messagebulk);
            // 消息的来源频道
            addReplyBulk(c,channel);
            // 消息内容
            addReplyBulk(c,message);

            // 接收客户端计数
            receivers++;
        }
    }

    /* Send to clients listening to matching channels */
    // 将消息也发送给那些和频道匹配的模式
    if (listLength(server.pubsub_patterns)) {

        // 遍历模式链表
        listRewind(server.pubsub_patterns,&li);
        channel = getDecodedObject(channel);
        while ((ln = listNext(&li)) != NULL) {

            // 取出 pubsubPattern
            pubsubPattern *pat = ln->value;

            // 如果 channel 和 pattern 匹配
            // 就给所有订阅该 pattern 的客户端发送消息
            if (stringmatchlen((char*)pat->pattern->ptr,
                                sdslen(pat->pattern->ptr),
                                (char*)channel->ptr,
                                sdslen(channel->ptr),0)) {

                // 回复客户端
                // 示例：
                // 1) "pmessage"
                // 2) "*"
                // 3) "xxx"
                // 4) "hello"
                addReply(pat->client,shared.mbulkhdr[4]);
                addReply(pat->client,shared.pmessagebulk);
                addReplyBulk(pat->client,pat->pattern);
                addReplyBulk(pat->client,channel);
                addReplyBulk(pat->client,message);

                // 对接收消息的客户端进行计数
                receivers++;
            }
        }

        decrRefCount(channel);
    }

    // 返回计数
    return receivers;
}

// Assembly:
pushq %rbp
pushq %r15
pushq %r14
pushq %r13
pushq %r12
pushq %rbx
subq $0x18, %rsp
movq %rsi, %rbx
movq %rdi, %r15
leaq 0x7f088(%rip), %r14     # 0xc6fa8
movq 0x7a8(%r14), %rdi
movq %r15, %rsi
callq 0x21b64
testq %rax, %rax
je 0x47fa0
movq 0x8(%rax), %rdi
leaq 0x8(%rsp), %r14
movq %r14, %rsi
callq 0x1ffac
xorl %ebp, %ebp
leaq 0x7f8b2(%rip), %r13     # 0xc7800
movq %r14, %rdi
callq 0x1ffc6
testq %rax, %rax
je 0x47f97
movq 0x10(%rax), %r12
movq 0x13a48(%r13), %rsi
movq %r12, %rdi
callq 0x2c10d
movq 0xf8(%r13), %rsi
movq %r12, %rdi
callq 0x2c10d
movq %r12, %rdi
movq %r15, %rsi
callq 0x2c84a
movq %r12, %rdi
movq %rbx, %rsi
callq 0x2c84a
incl %ebp
jmp 0x47f4e
leaq 0x7f00a(%rip), %r14     # 0xc6fa8
jmp 0x47fa2
xorl %ebp, %ebp
movq 0x7b0(%r14), %rdi
cmpq $0x0, 0x28(%rdi)
je 0x48055
leaq 0x8(%rsp), %r14
movq %r14, %rsi
callq 0x1ffac
movq %r15, %rdi
callq 0x2f087
movq %rax, %r15
leaq 0x7f82d(%rip), %r12     # 0xc7800
movq %r14, %rdi
callq 0x1ffc6
testq %rax, %rax
je 0x4804d
movq 0x10(%rax), %r13
movq 0x8(%r13), %rax
movq 0x8(%rax), %rdi
movl -0x8(%rdi), %esi
movq 0x8(%r15), %rdx
movl -0x8(%rdx), %ecx
xorl %r8d, %r8d
callq 0x2e0ec
testl %eax, %eax
je 0x47fd3
movq (%r13), %rdi
movq 0x13a50(%r12), %rsi
callq 0x2c10d
movq (%r13), %rdi
movq 0x100(%r12), %rsi
callq 0x2c10d
movq (%r13), %rdi
movq 0x8(%r13), %rsi
callq 0x2c84a
movq (%r13), %rdi
movq %r15, %rsi
callq 0x2c84a
movq (%r13), %rdi
movq %rbx, %rsi
callq 0x2c84a
incl %ebp
jmp 0x47fd3
movq %r15, %rdi
callq 0x2ee1f
movl %ebp, %eax
addq $0x18, %rsp
popq %rbx
popq %r12
popq %r13
popq %r14
popq %r15
popq %rbp
retq