我正在使用 XMPPFramework 在我的应用程序中实现群聊功能。一对一聊天工作正常,但是当我通过调用 [xmppRoom joinRoomUsingNickname] 加入房间时,流断开连接而没有给出任何错误。
我也实现了 xmppStreamDidDisconnect:withError,但它仍然给出 nil 错误。用户在加入房间后也会立即离开房间,因为流会断开连接。我也在使用重新连接模块,但是当它重新连接时,房间不会自动加入。
我也在用 pidgin 来测试它,但它在那里工作得很好。立即断开连接的原因可能是什么?
PS:我在运行 iOS 9.1 的 iPhone 5 上使用它进行测试
更新:现在出现以下错误 -
Error Domain=GCDAsyncSocketErrorDomain Code=7 "Socket closed by remote peer" UserInfo={NSLocalizedDescription=Socket closed by remote peer}
最佳答案
试试这个模块
MessageManager.h
// Created by Deepak MK on 27/11/15.
//
#import <UIKit/UIKit.h>
#import "XMPP.h"
#import <CoreData/CoreData.h>
#import "XMPPFramework.h"
#import "XMPPMessageDeliveryReceipts.h"
#import "XMPPLastActivity.h"
#import "XMPPRosterMemoryStorage.h"
#import "XMPPRoomMemoryStorage.h"
#import "XMPPvCardCoreDataStorage.h"
#import "XMPPvCardTemp.h"
/**
message manager class manage all message sequence.
*/
@interface MessageManager : NSObject
{
XMPPStream *xmppStream;
NSString *password;
BOOL isOpen;
BOOL isRegistering;
id _delgate;
XMPPRosterCoreDataStorage *xmppRosterStorage;
XMPPRoster *xmppRoster;
XMPPvCardCoreDataStorage* xmppvCardStorage;
XMPPvCardTempModule*xmppvCardTempModule;
}
+ (MessageManager *) sharedMessageHandler;
/**
The stream varible for connecting stream
*/
@property (nonatomic, readonly) XMPPStream *xmppStream;
/**
XMPPRoster varible
*/
@property (nonatomic, strong,readonly) XMPPRoster *xmppRoster;
/**
XMPPRosterCoreDataStorage varible
*/
@property (nonatomic, strong,readonly) XMPPRosterCoreDataStorage *xmppRosterStorage;
/**
XMPPRoom varible
*/
@property (nonatomic, strong, readonly) XMPPRoom *xmppRoom;
/**
Setting of delegate
@param delegate class delegate
*/
- (void) setdelegate:(id)delegate;
/**
Return of delegate
*/
- (id) delegate;
/**
connecting stream of Xmpp server
*/
- (void) setupStream;
/**
Connect user to Xmpp server
@param jabberID login user name
@param myPassword login password
*/
- (BOOL)connectWithUserId:(NSString*)jabberID withPassword:(NSString*)myPassword;
/**
Connect user to Xmpp server
@param userName login user name
@param myPassword login password
*/
- (void) authenticateUserWIthUSerName:(NSString*)userName withPassword:(NSString*)myPassword;
/**
disconnect user from Xmpp server
*/
- (void) disconnect;
/**
changes the presence to online
*/
- (void) goOnline;
/**
changes the presence to offline
*/
- (void) goOffline;
/**
Register new user to xmpp server
@param userName new user name
@param _password new password
@param EmailId new email id
*/
- (void)registerStudentWithUserName:(NSString *)userName withPassword:(NSString *)_password withEmailId:(NSString *)EmailId;
/**
send message to other user with content
@param toAdress destination address
@param content content of message
*/
- (BOOL)sendMessageTo:(NSString*)toAdress withContents:(NSString*)content;
/**
This method is used for sending subscribe invitation to user
@param userID destination address
*/
- (void) sendSubscribeMessageToUser:(NSString*)userID;
/**
This method is used for setting substate of presence
@param subState substate of user
*/
- (void) presenceWithStubState:(NSString*)subState;
/**
This method is used to create new room
@param ChatRoomJID New room name
*/
- (void) setUpRoom:(NSString *)ChatRoomJID;
/**
This method is used to destroyRoom
*/
- (void) destroyCreatedRoom;
/**
This method is used to send message to group
*/
- (BOOL)sendGroupMessageWithBody:(NSString*)_body;
- (void) requestAllMesssage;
@end
/**
Set of methods to be implemented to act as a restaurant patron
*/
@protocol MessageManagerDelegate <NSObject>
/**
Methods to be get state of stream
*/
- (void) didGetStreamState:(BOOL)state;
/**
Methods to be get state of Authentication
*/
- (void) didGetAuthenticationState:(BOOL)state;
/**
Methods to be get state of registration
*/
- (void) didGetRegistrationState:(BOOL)state WithErrorMessage:(NSString*)errorMessage;
/**
Methods to get recieved message
*/
- (void) didReceiveMessageWithBody:(NSString *) body;
/**
Methods to get presence of other user
*/
- (void) didRecievePresence:(NSString*)state withUserName:(NSString*)userName WithSubState:(NSString*)subState;
/**
Methods to get event of user joined room
*/
- (void) didCreatedOrJoinedRoomWithCreatedRoomName:(NSString*)_roomName;
- (void) didGetUserJoinedToRoomORLeaveRoomWithName:(NSString*)_userName WithPresence:(NSString*)presence;
@end
MessageManager.m
#import "MessageManager.h"
#import "DDLog.h"
#import "DDTTYLogger.h"
#import <CFNetwork/CFNetwork.h>
#if DEBUG
static const int ddLogLevel = LOG_LEVEL_VERBOSE;
#else
static const int ddLogLevel = LOG_LEVEL_INFO;
#endif
#define kBaseXMPPURL @"XXXXXXXXXX"
@interface MessageManager()
@end
static MessageManager *sharedMessageHandler = nil;
@implementation MessageManager
@synthesize xmppStream;
@synthesize xmppRoster;
@synthesize xmppRosterStorage;
@synthesize xmppRoom;
#pragma mark - self class Delegate
- (void) setdelegate:(id)delegate
{
_delgate= delegate;
}
- (id) delegate
{
return _delgate;
}
#pragma mark - custom Functions
+ (MessageManager *) sharedMessageHandler
{
if (sharedMessageHandler == nil)
{
sharedMessageHandler = [[super allocWithZone:NULL] init];
}
return sharedMessageHandler;
}
+ (id)allocWithZone:(NSZone *)zone {
return [self sharedMessageHandler];
}
- (id)copyWithZone:(NSZone *)zone {
return self;
}
#pragma mark - connection setup Functions
/**
This fuction is used to setup XMPP Stream
*/
- (void)setupStream
{
// Setup xmpp stream
//
// The XMPPStream is the base class for all activity.
// Everything else plugs into the xmppStream, such as modules/extensions and delegates.
xmppStream = [[XMPPStream alloc] init];
[xmppStream setHostName:kBaseXMPPURL];
[xmppStream addDelegate:self delegateQueue:dispatch_get_main_queue()];
}
/**
This fuction is used to Connect XMPP With userId and Password
*/
- (BOOL)connectWithUserId:(NSString*)jabberID withPassword:(NSString*)myPassword
{
[self setupStream];
isRegistering=NO;
if (![xmppStream isDisconnected]) {
return YES;
}
if (jabberID == nil || myPassword == nil) {
return NO;
}
[xmppStream setMyJID:[XMPPJID jidWithString:jabberID]];
password = myPassword;
NSError *error = nil;
if (![xmppStream connectWithTimeout:XMPPStreamTimeoutNone error:&error])
{
UIAlertView *alertView = [[UIAlertView alloc] initWithTitle:@"Error"
message:[NSString stringWithFormat:@"Can't connect to server %@", [error localizedDescription]]
delegate:nil
cancelButtonTitle:@"Ok"
otherButtonTitles:nil];
[alertView show];
return NO;
}
return YES;
}
- (void) authenticateUserWIthUSerName:(NSString*)userName withPassword:(NSString*)myPassword
{
if ([xmppStream isConnected])
{
NSError*error =nil;
[xmppStream setMyJID:[XMPPJID jidWithString:userName]];
[xmppStream authenticateWithPassword:myPassword error:&error];
}
else
{
[self connectWithUserId:userName withPassword:myPassword];
}
}
#pragma mark ---Delegate of Connect
/**
This fuction is called when stream is connected
*/
- (void)xmppStreamDidConnect:(XMPPStream *)sender {
isOpen = YES;
NSError *error = nil;
NSLog(@"Stream Connected");
if (!isRegistering)
{
if([[self delegate] respondsToSelector:@selector(didGetStreamState:)])
{
[[self delegate]didGetStreamState:YES];
}
[xmppStream authenticateWithPassword:password error:&error];
}
else
{
[xmppStream registerWithPassword:password error:&error];
}
}
/**
This fuction is called when User is Authenticated
*/
- (void)xmppStreamDidAuthenticate:(XMPPStream *)sender {
[self goOnline];
NSLog(@"Stream Authenticated");
if([[self delegate] respondsToSelector:@selector(didGetAuthenticationState:)])
{
[[self delegate]didGetAuthenticationState:YES];
}
// if ([xmppStream isAuthenticated]) {
// NSLog(@"authenticated");
// xmppvCardStorage = [[XMPPvCardCoreDataStorage alloc] initWithInMemoryStore];
// xmppvCardTempModule = [[XMPPvCardTempModule alloc] initWithvCardStorage:xmppvCardStorage];
// [xmppvCardTempModule activate:[self xmppStream]];
// [xmppvCardTempModule addDelegate:self delegateQueue:dispatch_get_main_queue()];
// [xmppvCardTempModule fetchvCardTempForJID:[sender myJID] ignoreStorage:YES];
// }
}
- (void)xmppvCardTempModule:(XMPPvCardTempModule *)vCardTempModule didReceivevCardTemp:(XMPPvCardTemp *)vCardTemp forJID:(XMPPJID *)jid{
NSLog(@"Delegate is called");
XMPPvCardTemp *vCard = [xmppvCardStorage vCardTempForJID:jid xmppStream:xmppStream];
NSLog(@"Stored card: %@",vCard);
NSLog(@"%@", vCard.description);
NSLog(@"%@", vCard.name);
NSLog(@"%@", vCard.emailAddresses);
NSLog(@"%@", vCard.formattedName);
NSLog(@"%@", vCard.givenName);
NSLog(@"%@", vCard.middleName);
}
/**
This fuction is called when User is not Authenticated
*/
- (void)xmppStream:(XMPPStream *)sender didNotAuthenticate:(NSXMLElement *)error
{
NSLog(@"Not Authenticated");
if([[self delegate] respondsToSelector:@selector(didGetAuthenticationState:)])
{
[[self delegate]didGetAuthenticationState:NO];
}
}
#pragma mark - Stream disconnection
/**
This fuction is used to disconnet user
*/
- (void)disconnect
{
[self goOffline];
[xmppStream disconnect];
}
#pragma mark ---Delegate of disconnect
/**
This fuction is called when stream is disConnected
*/
- (void)xmppStreamDidDisconnect:(XMPPStream *)sender withError:(NSError *)error
{
NSLog(@"Stream Disconnected");
if([[self delegate] respondsToSelector:@selector(didGetStreamState:)])
{
[[self delegate]didGetStreamState:NO];
}
}
#pragma mark - setting presence
/**
This fuction is used change the presence to online
*/
- (void)goOnline
{
XMPPPresence *presence = [XMPPPresence presence];
[xmppStream sendElement:presence];
}
/**
This fuction is used change the presence to Ofline
*/
- (void)goOffline
{
XMPPPresence *presence = [XMPPPresence presenceWithType:@"unavailable"];
[xmppStream sendElement:presence];
}
/**
This fuction is used change the presence substate
*/
- (void) presenceWithStubState:(NSString*)subState
{
XMPPPresence *presence = [XMPPPresence presence];// type="available" is implicit
NSXMLElement *status = [NSXMLElement elementWithName:@"status"];
[status setStringValue:subState];
[presence addChild:status];
[xmppStream sendElement:presence];
}
/**
This fuction is called when other user state is changed
*/
- (void)xmppStream:(XMPPStream *)sender didReceivePresence:(XMPPPresence *)presence
{
DDLogVerbose(@"%@: %@ - %@", THIS_FILE, THIS_METHOD, [presence fromStr]);
NSString *presenceType = [presence type]; // online/offline
NSString *myUsername = [[sender myJID] user];
NSString *presenceFromUser = [[presence from] user];
NSString* presenceState= [presence status];
NSLog(@"%@ is %@ state %@",presenceFromUser,presenceType,presenceState);
if (![presenceFromUser isEqualToString:myUsername])
{
if ([presenceType isEqualToString:@"available"])
{
if([[self delegate] respondsToSelector:@selector(didRecievePresence:withUserName:WithSubState:)])
{
[[self delegate] didRecievePresence:presenceType withUserName:presenceFromUser WithSubState:presenceState];
}
}
else if ([presenceType isEqualToString:@"unavailable"]) {
if([[self delegate] respondsToSelector:@selector(didRecievePresence:withUserName:WithSubState:)])
{
[[self delegate] didRecievePresence:presenceType withUserName:presenceFromUser WithSubState:presenceState];
}
}
else if ([presenceType isEqualToString:@"subscribe"])
{
[xmppRoster subscribePresenceToUser:[presence from]];
[self goOnline];
}
else if ([presenceType isEqualToString:@"subscribed"])
{
[xmppRoster subscribePresenceToUser:[presence from]];
}
}
if (xmppRoom)
{
[xmppRoom fetchMembersList];
}
}
#pragma mark - subscription
- (void) sendSubscribeMessageToUser:(NSString*)userID
{
XMPPJID* jbid= [XMPPJID jidWithString:userID];
XMPPPresence *presence = [XMPPPresence presenceWithType:@"subscribe" to:jbid];
[xmppStream sendElement:presence];
}
#pragma mark - XMPP delegates
/**
This fuction is called when new IQ is received
*/
- (BOOL)xmppStream:(XMPPStream *)sender didReceiveIQ:(XMPPIQ *)iq {
return NO;
}
#pragma mark - RegistrationFunction
/**
This fuction is user to retister new user
if stream is connected the it will directly call registeration function
otherwise it will connect stream and then call registeration process
*/
- (void)registerStudentWithUserName:(NSString *)userName withPassword:(NSString *)_password withEmailId:(NSString *)EmailId
{
if (xmppStream==nil)
{
[self setupStream];
}
[xmppStream setMyJID:[XMPPJID jidWithString:userName]];
NSLog(@"Attempting registration for username %@",xmppStream.myJID.bare);
password=_password;
NSError *error = nil;
BOOL success;
if(![ xmppStream isConnected])
{
success = [[self xmppStream] connectWithTimeout:XMPPStreamTimeoutNone error:&error];
isRegistering=YES;
}
else
{
success = [[self xmppStream] registerWithPassword:_password error:&error];
}
if (success)
{
NSLog(@"succeed ");
isRegistering=YES;
}
else
{
if([[self delegate] respondsToSelector:@selector(didGetRegistrationState:WithErrorMessage:)])
{
[[self delegate]didGetRegistrationState:YES WithErrorMessage:@"Stream not connected"];
}
}
}
#pragma mark ---delegates of registrtaion
/**
This fuction is called when new user is registered
*/
- (void)xmppStreamDidRegister:(XMPPStream *)sender{
if([[self delegate] respondsToSelector:@selector(didGetRegistrationState:WithErrorMessage:)])
{
[[self delegate]didGetRegistrationState:YES WithErrorMessage:@"Registration with XMPP Successful!"];
}
}
/**
This fuction is called when registeration process failed
*/
- (void)xmppStream:(XMPPStream *)sender didNotRegister:(NSXMLElement *)error{
// DDXMLElement *errorXML = [error elementForName:@"error"];
// NSString *errorCode = [[errorXML attributeForName:@"code"] stringValue];
// NSString *regError = [NSString stringWithFormat:@"ERROR :- %@",error.description];
//
//
// if([errorCode isEqualToString:@"409"])
// {
// regError=@"Username Already Exists!";
// }
// else
// {
// regError= @"Server not connected";
// }
if([[self delegate] respondsToSelector:@selector(didGetRegistrationState:WithErrorMessage:)])
{
[[self delegate]didGetRegistrationState:NO WithErrorMessage:@"Username Already Exists!"];
}
}
#pragma mark - send and recieve message
/**
This fuction is used to send message to other user with contents of body
*/
//-(void)sendMessageTo:(NSString*)toAdress withContents:(NSString*)messageStr
//{
//
//
// if([messageStr length]> 0)
// {
//
// NSXMLElement *body = [NSXMLElement elementWithName:@"body"];
// [body setStringValue:messageStr];
//
// NSXMLElement *message = [NSXMLElement elementWithName:@"message"];
// [message addAttributeWithName:@"type" stringValue:@"chat"];
// [message addAttributeWithName:@"to" stringValue:toAdress];
// [message addChild:body];
//
// [self.xmppStream sendElement:message];
// }
//}
- (BOOL)sendMessageTo:(NSString*)toAdress withContents:(NSString*)content
{
if([content length]> 0)
{
NSXMLElement *body = [NSXMLElement elementWithName:@"body"];
[body setStringValue:content];
NSXMLElement *message = [NSXMLElement elementWithName:@"message"];
[message addAttributeWithName:@"type" stringValue:@"chat"];
[message addAttributeWithName:@"to" stringValue:toAdress];
[message addChild:body];
[self.xmppStream sendElement:message];
}
return YES;
}
#pragma mark recieve message
/**
This fuction is called when new message arrived
*/
- (void)xmppStream:(XMPPStream *)sender didReceiveMessage:(XMPPMessage *)message
{
DDLogVerbose(@"%@: %@", THIS_FILE, THIS_METHOD);
// A simple example of inbound message handling.
if ([message body])
{
NSString *body = [[message elementForName:@"body"] stringValue];
if([[self delegate] respondsToSelector:@selector(didReceiveMessageWithBody:)])
{
[[self delegate] didReceiveMessageWithBody:body];
}
}
}
#pragma mark - create new room
/**
This fuction is used to setup room with roomId
*/
-(void)setUpRoom:(NSString *)ChatRoomJID
{
if (!ChatRoomJID)
{
return;
}
// Configure xmppRoom
XMPPRoomMemoryStorage *roomMemoryStorage = [[XMPPRoomMemoryStorage alloc] init];
XMPPJID *roomJID = [XMPPJID jidWithString:ChatRoomJID];
xmppRoom = [[XMPPRoom alloc] initWithRoomStorage:roomMemoryStorage jid:roomJID dispatchQueue:dispatch_get_main_queue()];
[xmppRoom activate:xmppStream];
[xmppRoom addDelegate:self delegateQueue:dispatch_get_main_queue()];
NSXMLElement *history = [NSXMLElement elementWithName:@"history"];
[history addAttributeWithName:@" maxchars" stringValue:@"0"];
[xmppRoom joinRoomUsingNickname:xmppStream.myJID.user
history:history
password:nil];
[self performSelector:@selector(ConfigureNewRoom:) withObject:nil afterDelay:4];
}
/**
This fuction is used configure new
*/
- (void)ConfigureNewRoom:(id)sender
{
[xmppRoom configureRoomUsingOptions:nil];
[xmppRoom fetchConfigurationForm];
[xmppRoom fetchBanList];
[xmppRoom fetchMembersList];
[xmppRoom fetchModeratorsList];
}
/**
This fuction is called when new room is created
*/
- (void)xmppRoomDidCreate:(XMPPRoom *)sender
{
DDLogInfo(@"%@: %@", THIS_FILE, THIS_METHOD);
// I am inviting friends after room is created
}
/**
This fuction is called when user joined room
*/
- (void)xmppRoomDidJoin:(XMPPRoom *)sender
{
[sender fetchMembersList];
[sender fetchConfigurationForm];
[self requestAllMesssage];
DDLogInfo(@"%@: %@", THIS_FILE, THIS_METHOD);
if([[self delegate] respondsToSelector:@selector(didCreatedOrJoinedRoomWithCreatedRoomName:)])
{
[[self delegate] didCreatedOrJoinedRoomWithCreatedRoomName:sender.myRoomJID.bare];
}
}
- (void)xmppRoom:(XMPPRoom *)sender didFetchMembersList:(NSArray *)items
{
}
- (void)xmppRoom:(XMPPRoom *)sender occupantDidJoin:(XMPPJID *)occupantJID withPresence:(XMPPPresence *)presence
{
if([[self delegate] respondsToSelector:@selector(didGetUserJoinedToRoomORLeaveRoomWithName:WithPresence:)])
{
// id details =occupantJID;
// NSString* string = (NSString*)details;
[[self delegate] didGetUserJoinedToRoomORLeaveRoomWithName:[occupantJID resource] WithPresence:[presence type]];
}
}
- (void)xmppRoom:(XMPPRoom *)sender occupantDidLeave:(XMPPJID *)occupantJID withPresence:(XMPPPresence *)presence
{
if([[self delegate] respondsToSelector:@selector(didGetUserJoinedToRoomORLeaveRoomWithName:WithPresence:)])
{
[[self delegate] didGetUserJoinedToRoomORLeaveRoomWithName:[occupantJID resource] WithPresence:[presence type]];
}
}
- (void)xmppRoom:(XMPPRoom *)sender occupantDidUpdate:(XMPPJID *)occupantJID withPresence:(XMPPPresence *)presence
{
if([[self delegate] respondsToSelector:@selector(didGetUserJoinedToRoomORLeaveRoomWithName:WithPresence:)])
{
[[self delegate] didGetUserJoinedToRoomORLeaveRoomWithName:[occupantJID resource] WithPresence:[presence type]];
}
}
- (void) requestAllMesssage
{
// <presence
// from='hag66@shakespeare.lit/pda'
// id='n13mt3l'
// to='coven@chat.shakespeare.lit/thirdwitch'>
// <x xmlns='http://jabber.org/protocol/muc'>
// <history since='1970-01-01T00:00:00Z'/>
// </x>
// </presence>
//
// NSXMLElement *iQ = [NSXMLElement elementWithName:@"presence"];
// [iQ addAttributeWithName:@"type" stringValue:@"get"];
// [iQ addAttributeWithName:@"id" stringValue:@"n13mt3l"];
//
// NSXMLElement *retrieve = [NSXMLElement elementWithName:@"retrieve"];
// [retrieve addAttributeWithName:@"xmlns" stringValue:@"urn:xmpp:archive"];
// [retrieve addAttributeWithName:@"history since" stringValue:@"1970-01-01T00:00:00Z"];
//
// NSXMLElement *set = [NSXMLElement elementWithName:@"set"];
// [set addAttributeWithName:@"xmlns" stringValue:@"http://jabber.org/protocol/muc"];
//
// [retrieve addChild:set];
// [iQ addChild:retrieve];
//
// [xmppStream sendElement:iQ];
}
- (void)xmppRoom:(XMPPRoom *)sender didFetchConfigurationForm:(NSXMLElement *)configForm
{
DDLogInfo(@"%@: %@", THIS_FILE, THIS_METHOD);
NSXMLElement *newConfig = [configForm copy];
NSArray *fields = [newConfig elementsForName:@"field"];
for (NSXMLElement *field in fields)
{
NSString *var = [field attributeStringValueForName:@"var"];
// Make Room Persistent
if ([var isEqualToString:@"muc#roomconfig_persistentroom"])
{
[field removeChildAtIndex:0];
[field addChild:[NSXMLElement elementWithName:@"value" stringValue:@"1"]];
}
if ([var isEqualToString:@"roomconfig_enablelogging"])
{
[field removeChildAtIndex:0];
[field addChild:[NSXMLElement elementWithName:@"value" stringValue:@"1"]];
}
if ([var isEqualToString:@"muc#roomconfig_maxusers"])
{
[field removeChildAtIndex:0];
[field addChild:[NSXMLElement elementWithName:@"value" stringValue:@"100"]];
}
}
// [sender configureRoomUsingOptions:newConfig];
}
/**
This fuction is used to destroy created room
*/
- (void) destroyCreatedRoom
{
[xmppRoom destroyRoom];
}
- (BOOL)sendGroupMessageWithBody:(NSString*)_body
{
[xmppRoom sendMessageWithBody:_body];
return YES;
}
@end
关于ios - XMPP Stream 在加入 MUC 房间时断开连接,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/34610863/
Arel3.0.2提供了两个类来指定连接类型:Arel::Nodes::InnerJoin和Arel::Nodes::OuterJoin并使用InnerJoin默认。foo=Arel::Table.new('foo')bar=Arel::Table.new('bar')foo.join(bar,Arel::Nodes::InnerJoin)#innerfoo.join(bar,Arel::Nodes::OuterJoin)#outerfoo.join(bar,???)#left如果要生成左连接,如何连接两个表? 最佳答案 你可以使用
我正在使用Sequel构建一个愿望list系统。我有一个wishlists和itemstable和一个items_wishlists连接表(该名称是续集选择的名称)。items_wishlists表还有一个用于facebookid的额外列(因此我可以存储opengraph操作),这是一个NOTNULL列。我还有Wishlist和Item具有续集many_to_many关联的模型已建立。Wishlist类也有:selectmany_to_many关联的选项设置为select:[:items.*,:items_wishlists__facebook_action_id].有没有一种方法可以
我使用的是Firefox版本36.0.1和Selenium-Webdrivergem版本2.45.0。我能够创建Firefox实例,但无法使用脚本继续进行进一步的操作无法在60秒内获得稳定的Firefox连接(127.0.0.1:7055)错误。有人能帮帮我吗? 最佳答案 我遇到了同样的问题。降级到firefoxv33后一切正常。您可以找到旧版本here 关于ruby-无法在60秒内获得稳定的Firefox连接(127.0.0.1:7055),我们在StackOverflow上找到一个类
这里有一个很好的答案解释了如何在Ruby中下载文件而不将其加载到内存中:https://stackoverflow.com/a/29743394/4852737require'open-uri'download=open('http://example.com/image.png')IO.copy_stream(download,'~/image.png')我如何验证下载文件的IO.copy_stream调用是否真的成功——这意味着下载的文件与我打算下载的文件完全相同,而不是下载一半的损坏文件?documentation说IO.copy_stream返回它复制的字节数,但是当我还没有下
我正在尝试解析一个文本文件,该文件每行包含可变数量的单词和数字,如下所示:foo4.500bar3.001.33foobar如何读取由空格而不是换行符分隔的文件?有什么方法可以设置File("file.txt").foreach方法以使用空格而不是换行符作为分隔符? 最佳答案 接受的答案将slurp文件,这可能是大文本文件的问题。更好的解决方案是IO.foreach.它是惯用的,将按字符流式传输文件:File.foreach(filename,""){|string|putsstring}包含“thisisanexample”结果的
1.错误信息:Errorresponsefromdaemon:Gethttps://registry-1.docker.io/v2/:net/http:requestcanceledwhilewaitingforconnection(Client.Timeoutexceededwhileawaitingheaders)或者:Errorresponsefromdaemon:Gethttps://registry-1.docker.io/v2/:net/http:TLShandshaketimeout2.报错原因:docker使用的镜像网址默认为国外,下载容易超时,需要修改成国内镜像地址(首先阿里
require"socket"server="irc.rizon.net"port="6667"nick="RubyIRCBot"channel="#0x40"s=TCPSocket.open(server,port)s.print("USERTesting",0)s.print("NICK#{nick}",0)s.print("JOIN#{channel}",0)这个IRC机器人没有连接到IRC服务器,我做错了什么? 最佳答案 失败并显示此消息::irc.shakeababy.net461*USER:Notenoughparame
print"Enteryourpassword:"pass=STDIN.noecho(&:gets)puts"Yourpasswordis#{pass}!"输出:Enteryourpassword:input.rb:2:in`':undefinedmethod`noecho'for#>(NoMethodError) 最佳答案 一开始require'io/console'后来的Ruby1.9.3 关于ruby-为什么不能使用类IO的实例方法noecho?,我们在StackOverflow上
考虑一下:现在这些情况:#output:http://domain.com/?foo=1&bar=2#output:http://domain.com/?foo=1&bar=2#output:http://domain.com/?foo=1&bar=2#output:http://domain.com/?foo=1&bar=2我需要用其他字符串输出URL。我如何保证&符号不会被转义?由于我无法控制的原因,我无法发送&。求助!把我的头发拉到这里:\编辑:为了澄清,我实际上有一个像这样的数组:@images=[{:id=>"fooid",:url=>"http://
我有一个super简单的脚本,它几乎包含了FayeWebSocketGitHub页面上用于处理关闭连接的内容:ws=Faye::WebSocket::Client.new(url,nil,:headers=>headers)ws.on:opendo|event|p[:open]#sendpingcommand#sendtestcommand#ws.send({command:'test'}.to_json)endws.on:messagedo|event|#hereistheentrypointfordatacomingfromtheserver.pJSON.parse(event.d