【问题标题】:Ruby callback function to continue execution of another functionRuby 回调函数继续执行另一个函数
【发布时间】:2013-03-06 15:29:37
【问题描述】:

我正在使用 Pubnub 将实时消息从服务器发布到客户端(浏览器页面)。使用 Pubnub 时,必须遵守它们的消息大小限制,有时会导致需要对消息进行分块、分段发送,然后在客户端进行重构。按照 Pubnub 的建议,如果Pubnub.publish() 函数没有被调用太快(即,如果消息片段只是通过 for 循环泵送),则可以确保传递消息的每个块。

Pubnub Ruby API 在Pubnub.publish() 中指定了 3 个必需参数、一个通道、一个消息和一个回调函数。下面显示的回调函数来自 Pubnub 的 Ruby 示例:

    @my_callback = lambda { |message| puts(message) }
    pn.publish(:channel => :hello_world,
      :message => "hi",
      :callback => @my_callback)

回调中的message(不是发布中的“hi”消息),包含publish()调用的状态信息,其值为“sent”和“message to large”,两者都将伴随一个唯一标识符。

所以在 Pubnub 引擎盖下的某个地方,这个回调得到了 .call() - 我想知道是否有办法让我进入这个过程。更详细地说,假设我有一条消息需要分成三个块,我想发送块 0,并且在回调中收到“已发送”状态后,我想发送块 1,等等……

我对 lambda 函数及其作用域不是很熟悉,这是我的第一次尝试:

    @my_callback = lambda { |message| 
                            puts(message) 
                            Rails.logger.debug("Setting pubnub_do_send to true from callback")
                            pubnub_do_send = true
                          }

    pubnub_do_send = true

    while !pubnub_message.nil?
      if pubnub_do_send 

        #Send pubnub message
        #Cut off first chunk of message (this is why I'm testing for nil)
        #Set pubnub_do_send to false

        Rails.logger.debug("Message #{message_id} chunk #{chunk_id} sent")
        pubnub_do_send = false
      end
    end

这导致了彻底的失败——让服务器完全锁定在一个无限的 while 循环中,因为(如果我不得不猜测的话)pubnub_do_send 再也没有设置为 true。查看调试日志,我看到第一条消息打印(“消息 1 块 0 已发送”),但从未看到回调函数的输出。 (可能是因为它所在的无限循环)

必须有一个干净的方法来做到这一点,我可以在某种程度上重构代码,先将消息分块并存储到一个数组中,然后简单地遍历数组进行发送,但我觉得解决方案离我们不远了,我只是不太擅长 lambda 函数和回调。

我觉得解决方案应该是这样的:

    @my_callback = lambda { |message| 
                            puts(message) 
                            send_pubnub_message(message_id, chunk_id, chunk)
                          }

    def send_pubnub_message(message_id, chunk_id, chunk)
      #Send pubnub message
      #Send message_id, next chunk_id, and next chunk to my_callback
    end

但问题是 my_callback 被 Pubnub 调用时 Pubnub.publish() 得到一些关于消息的状态而不是我直接调用它! (有没有办法让我将 message_id、chunk_id 和 chunk 插入回调仍然让 pubnub 将其消息附加到混音中?这听起来很错误,但可能是 Ruby...)

提前感谢所有帮助。

【问题讨论】:

    标签: ruby lambda callback pubnub


    【解决方案1】:

    您不应该尝试在回调中处理消息块状态。它只有一个职责,通知发布的状态。但是,您可以在消息中插入内容。我可能会创建一个知道当前状态的消息包装器,然后在 lambda 中发送它,这样您就不必跟踪它。我没有测试过下面的代码,但这里有一个我正在谈论的例子:

    class Message
      attr_accessor :id, :message, :chunked_message, :chunk_id
      def initialize(id, message)
        @id, @message = id, message
        chunk_message
      end
      def current_chunk
        @chunked_message[@chunk_id]
      end
      def next_chunk
        @chunk_id += 1
        self
      end
      def more?
        @chunked_message.length > chunk_id
      end
      private
      def chunk_message 
        implement splitting message here
      end
    end 
    
    
    def send_pubnub_message(message)
      pn.publish(:channel => :hello_world,
      :message => message.current_chunk
      :callback => lambda { |status| 
                            puts(status)
                            case status[0] // 1 = success, 0 = fail
                            when 1
                              send_pubnub_message(message.next_chunk) if message.more?
                            when 0
                              handle_pubnub_error(status[1], message)
                            end
                          }
    end
    

    【讨论】:

    • 看起来是一个不错的解决方案,我会立即实施 - 谢谢!
    • 其实这看起来像一个Model方法,对吗?我打算在控制器中实现,我想我仍然可以,只是想知道你把它变成模型方法的想法是什么。
    • 是的,模型是正确的地方。我不知道你的架构,所以这只是最简洁的演示方式
    • 我继续在控制器中实现并使其全部正常工作(您的答案被接受 - 再次感谢!),也许这可以纳入您的答案而不是在 cmets 中解释,但为什么你说模型是正确的地方? “生态系统”目前是一个发布到MessagesController 的设备,其中Message 被保存到数据库中,但我在保存后在控制器中发送 pubnub 消息,而不是在保存后的模型中发送......
    猜你喜欢
    • 2013-03-31
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-10-06
    • 1970-01-01
    • 2021-04-09
    • 1970-01-01
    相关资源
    最近更新 更多