gpt4 book ai didi

ruby-on-rails - 从 iOS 应用程序连接到 ActionCable

转载 作者:行者123 更新时间:2023-12-03 13:34:04 25 4
gpt4 key购买 nike

我一整天都被困在这个问题上。我有一个非常简单的 ActionCable 示例应用程序(聊天应用程序),作者是 David Heinemeier Hansson(https://www.youtube.com/watch?v=n0WUjGkDFS0)。

我正在尝试使用 iPhone 应用程序连接 websocket。当我连接到 ws://localhost:3000/cable 时,我能够接收到 ping ,但我不太确定如何从 javascript 上下文之外订阅 channel 。

最佳答案

哦,伙计,我在阅读这个问题后也遇到了这个问题。

过了一会儿,我终于找到了这个神奇的 Github 问题页面:

https://github.com/rails/rails/issues/22675

I do understand that this patch would break some tests. That is not surprising to me. But the original issue I believe is still relevant and shouldn't be closed.

The following JSON sent to the server should succeed:

{"command": "subscribe","identifier":{"channel":"ChangesChannel"}}

It does not! Instead you must send this:

{"command": "subscribe","identifier":"{\"channel\":\"ChangesChannel\"}"}



根据 Github 用户关于 Rails 问题的建议,我终于让 iOS 应用程序订阅了房间 channel 。

我的设置如下:
  • objective-c
  • 使用 PocketSocket 框架进行 web socket 连接
  • rails 5 RC1
  • ruby 2.2.4p230

  • 我假设你知道如何使用 Cocoapods 来安装 PocketSocket。

    相关代码如下:

    View Controller .h
    #import <PocketSocket/PSWebSocket.h>

    @interface ViewController : UIViewController <PSWebSocketDelegate, UITableViewDelegate, UITableViewDataSource, UITextFieldDelegate>

    @property (nonatomic, strong) PSWebSocket *socket;

    View Controller .m
    - (void)viewDidLoad {
    [super viewDidLoad];
    // Do any additional setup after loading the view, typically from a nib.

    [self initViews];
    [self initConstraints];
    [self initSocket];
    }

    -(void)initSocket
    {
    NSURLRequest *request = [NSURLRequest requestWithURL:[NSURL URLWithString:@"ws://localhost:3000/cable"]];

    self.socket = [PSWebSocket clientSocketWithRequest:request];
    self.socket.delegate = self;

    [self.socket open];
    }

    -(void)joinChannel:(NSString *)channelName
    {
    NSString *strChannel = @"{ \"channel\": \"RoomChannel\" }";

    id data = @{
    @"command": @"subscribe",
    @"identifier": strChannel
    };

    NSData * jsonData = [NSJSONSerialization dataWithJSONObject:data options:0 error:nil];
    NSString * myString = [[NSString alloc] initWithData:jsonData encoding:NSUTF8StringEncoding];

    NSLog(@"myString= %@", myString);

    [self.socket send:myString];
    }

    #pragma mark - PSWebSocketDelegate Methods -

    -(void)webSocketDidOpen:(PSWebSocket *)webSocket
    {
    NSLog(@"The websocket handshake completed and is now open!");

    [self joinChannel:@"RoomChannel"];
    }

    -(void)webSocket:(PSWebSocket *)webSocket didReceiveMessage:(id)message
    {
    NSData *data = [message dataUsingEncoding:NSUTF8StringEncoding];
    id json = [NSJSONSerialization JSONObjectWithData:data options:0 error:nil];

    NSString *messageType = json[@"type"];

    if(![messageType isEqualToString:@"ping"] && ![messageType isEqualToString:@"welcome"])
    {
    NSLog(@"The websocket received a message: %@", json[@"message"]);

    [self.messages addObject:json[@"message"]];
    [self.tableView reloadData];
    }
    }

    -(void)webSocket:(PSWebSocket *)webSocket didFailWithError:(NSError *)error
    {
    NSLog(@"The websocket handshake/connection failed with an error: %@", error);
    }

    -(void)webSocket:(PSWebSocket *)webSocket didCloseWithCode:(NSInteger)code reason:(NSString *)reason wasClean:(BOOL)wasClean
    {
    NSLog(@"The websocket closed with code: %@, reason: %@, wasClean: %@", @(code), reason, (wasClean) ? @"YES": @"NO");
    }

    重要的提示:

    我还深入研究了订阅类源代码:
    def add(data)
    id_key = data['identifier']
    id_options = ActiveSupport::JSON.decode(id_key).with_indifferent_access

    subscription_klass = connection.server.channel_classes[id_options[:channel]]

    if subscription_klass
    subscriptions[id_key] ||= subscription_klass.new(connection, id_key, id_options)
    else
    logger.error "Subscription class not found (#{data.inspect})"
    end
    end

    注意这一行:
    connection.server.channel_classes[id_options[:channel]]

    我们需要使用 channel 的类名。

    DHH youtube 视频使用“room_channel”作为房间名称,但该 channel 的类文件名为“RoomChannel”。

    我们需要使用类名而不是 channel 的实例名。

    发送消息

    以防万一其他人也想知道如何发送消息,这里是我的 iOS 代码,用于向服务器发送消息:
    -(void)sendMessage:(NSString *)message
    {
    NSString *strMessage = [[NSString alloc] initWithFormat:@"{ \"action\": \"speak\", \"message\": \"%@\" }", message];

    NSString *strChannel = @"{ \"channel\": \"RoomChannel\" }";

    id data = @{
    @"command": @"message",
    @"identifier": strChannel,
    @"data": strMessage
    };

    NSData * jsonData = [NSJSONSerialization dataWithJSONObject:data options:0 error:nil];
    NSString * myString = [[NSString alloc] initWithData:jsonData encoding:NSUTF8StringEncoding];

    NSLog(@"myString= %@", myString);

    [self.socket send:myString];
    }

    这假设您已经连接了 UITextField 来处理按下返回键或 UI 上某处的某个“发送”按钮。

    整个演示应用程序是一个快速的 hack,显然,如果我要在一个真正的应用程序中做它,我会让我的代码更干净,更可重用并将它抽象成一个类。

    从真实的 iPhone 设备连接到 Rails 服务器:

    为了让 iPhone 应用程序与真实设备上的 Rails 服务器通信,而不是 iPhone 模拟器。

    请执行下列操作:
  • 检查计算机的 TCP/IP 地址。例如,在我的 iMac 上,某些日子可能是 10.1.1.10(如果使用 DHCP,将来可能会自动更改)。
  • 编辑您的 Rail config > environment > development.rb文件并将以下行放在 end 之前的某处关键词:
    Rails.application.config.action_cable.allowed_request_origins = ['http://10.1.1.10:3000']
  • 使用以下命令启动 Rails 服务器:
    rails server -b 0.0.0.0
  • 在 iPhone 设备上构建并运行您的 iPhone 应用程序。您现在应该可以连接和发送消息了 :D

  • 我从以下链接获得了这些解决方案:

    Request origin not allowed: http://localhost:3001 when using Rails5 and ActionCable

    Rails 4.2 server; private and public ip not working

    希望以后能帮助到其他人。

    关于ruby-on-rails - 从 iOS 应用程序连接到 ActionCable,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/35145429/

    25 4 0
    Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
    广告合作:1813099741@qq.com 6ren.com