Skip Menu |

This queue is for tickets about the Mail-IMAPClient CPAN distribution.

Report information
The Basics
Id: 30588
Status: resolved
Priority: 0/
Queue: Mail-IMAPClient

People
Owner: Nobody in particular
Requestors: polettix [...] cpan.org
Cc:
AdminCc:

Bug Information
Severity: Wishlist
Broken in: 2.99_02
Fixed in: (no value)



Hi, using one's own socket is a nightmare at the moment: you have to setup the socket (fair), tell the client which socket to use (fair), put the client in Mail::IMAPClient::Connected state (not so fair), explicitly get rid of the server welcome message before doing anything with the client (ABSOLUTELY NOT fair). At the moment, the connect() method does two things: create an IO::Socket::INET object and initialise the IMAP connection (dealing with the server welcome message), then optionally call login() if some conditions apply. I'd suggest factoring out the initialisation part into another method that gets called by connect(), and that can be called by anyone wishing to provide her own socket (i.e. using IO::Socket::SSL). The Socket() method would probably be the best choice for this task, but it would break the current semantics so the decision is really up to you... the maintainer. The attached patch does exactly this, I called the new method "use_socket" for lack of a better name. With it, you can do: my $imap = Mail::IMAPClient->new(%imapargs); $imap->use_socket(IO::Socket::SSL->new(%args)); and connect via SSL :) It would be great to have such feature directly in the constructor, something like: my $imap = Mail::IMAPClient->new( %imapargs, UseSocket => IO::Socket::SSL->new(%sslargs), ); I also changed a bit in $code extraction and verification, in particular there were errors in how $code was checked: * the regexes lacked the /i modifier, which is present in the $code extraction line; * the alternative for "NO" had a stray space. Regards, Flavio.
Subject: IMAPClient.pm.diff
--- IMAPClient.pm.orig 2007-11-08 21:32:55.464707168 +0100 +++ IMAPClient.pm 2007-11-08 21:48:25.905258704 +0100 @@ -248,34 +248,42 @@ unless($sock) { $self->LastError("Unable to connect to $server: $@"); return undef; } $self->_debug("Connected to $server"); + + return $self->use_socket($sock); +} + +sub use_socket { + my $self = shift; + my ($sock) = @_; + $self->Socket($sock); $self->State(Connected); my $code; LINE: while(my $output = $self->_read_line) { foreach my $o (@$output) { $self->_record($self->Count, $o); next unless $o->[TYPE] eq "OUTPUT"; - $code = $o->[DATA] =~ /^\*\s+(OK|BAD|NO|PREAUTH)/i ? $1 : undef; + $code = $o->[DATA] =~ /^\*\s+(OK|BAD|NO|PREAUTH)/i ? uc($1) : undef; last LINE; } } $code or return undef; - if($code =~ /BYE|NO /) + if(($code eq 'BYE') || ($code eq 'NO')) { $self->State(Unconnected); return undef; } - if($code =~ /PREAUTH/ ) + if($code eq 'PREAUTH' ) { $self->State(Authenticated); return $self; } $self->User && $self->Password ? $self->login : $self; }
Subject: Re: [rt.cpan.org #30588]
Date: Thu, 8 Nov 2007 22:58:53 +0100
To: via RT <bug-Mail-IMAPClient [...] rt.cpan.org>
From: Mark Overmeer <solutions [...] overmeer.net>
* via RT (bug-Mail-IMAPClient@rt.cpan.org) [071108 21:13]: Show quoted text
> Thu Nov 08 16:13:12 2007: Request 30588 was acted upon. > Transaction: Ticket created by POLETTIX > Queue: Mail-IMAPClient > Broken in: 2.99_02
Show quoted text
> using one's own socket is a nightmare at the moment:
I agree Show quoted text
> my $imap = Mail::IMAPClient->new( > %imapargs, > UseSocket => IO::Socket::SSL->new(%sslargs), > );
Wouldn't it be nicer to call use_socket always when a socket is passed in? You know: this will be version 3.0 of the module, which is a major next release... small interface changes are permitted. Show quoted text
> I also changed a bit in $code extraction and verification, in particular > there were errors in how $code was checked: > > * the regexes lacked the /i modifier, which is present in the $code > extraction line; > * the alternative for "NO" had a stray space.
Gladly accepted. Could you also take a look at the documentation about this subject, in the pod file. -- Thanks for the patch, MarkOv ------------------------------------------------------------------------ Mark Overmeer MSc MARKOV Solutions Mark@Overmeer.net solutions@overmeer.net http://Mark.Overmeer.net http://solutions.overmeer.net
Subject: Proposed change to Socket method/parameter
From: POLETTIX [...] cpan.org
Show quoted text
> Wouldn't it be nicer to call use_socket always when a socket is > passed in? You know: this will be version 3.0 of the module, which > is a major next release... small interface changes are permitted.
Following your suggestion, I attach a new patch that does the following: * rename the previous "Socket" method to "RawSocket" * handle a "RawSocket" parameter in the constructor * change "Socket" method/parameter semantics according to what we're discussing. In particular, the connect() method ends with a call to Socket() to complete the initialisation phase and call login() if applicable. * changed the documentation where (I thought) it was due. I added documentation for the new "RawSocket" and changed the documentation for "Socket", pointing out the changed semantics. The attached patch also fixes a couple of bugs in _read_line(). There was also a bug in t/basic.t by the way, as you can see from the patch. Are these bugs a leftover of your overall code revision/rewrite? Cheers, Flavio. PS: I apologise for not filling a "Subject" line in my first post, I hate when this happens...
diff -r -u Mail-IMAPClient-2.99_02/lib/Mail/IMAPClient.pm Mail-IMAPClient-2.99_02-NewSocket/lib/Mail/IMAPClient.pm --- Mail-IMAPClient-2.99_02/lib/Mail/IMAPClient.pm 2007-10-26 11:46:16.000000000 +0200 +++ Mail-IMAPClient-2.99_02-NewSocket/lib/Mail/IMAPClient.pm 2007-11-09 16:33:13.260957272 +0100 @@ -108,7 +108,7 @@ # removed sub EnableServerResponseInLiteral {undef} -sub Socket(;$) +sub RawSocket(;$) { my ($self, $sock) = @_; defined $sock or return $self->{Socket}; @@ -222,7 +222,14 @@ } if($self->{Socket}) { $self->Socket($self->{Socket}) } - elsif($self->{Server}) { return $self->connect } + + if($self->{Rawsocket}) { + my $sock = delete $self->{Rawsocket}; + # Ignore Rawsocket if Socket has already been set -- TODO carp/croak? + $self->RawSocket($sock) unless $self->{Socket}; + } + + if(!$self->{Socket} && $self->{Server}) { return $self->connect } $self; } @@ -251,7 +258,16 @@ } $self->_debug("Connected to $server"); - $self->Socket($sock); + + return $self->Socket($sock); +} + +sub Socket +{ my ($self, $sock) = @_; + defined $sock + or return $self->{Socket}; + + $self->RawSocket($sock); $self->State(Connected); my $code; @@ -261,18 +277,18 @@ { $self->_record($self->Count, $o); next unless $o->[TYPE] eq "OUTPUT"; - $code = $o->[DATA] =~ /^\*\s+(OK|BAD|NO|PREAUTH)/i ? $1 : undef; + $code = $o->[DATA] =~ /^\*\s+(OK|BAD|NO|PREAUTH)/i ? uc($1) : undef; last LINE; } } $code or return undef; - if($code =~ /BYE|NO /) + if(($code eq 'BYE') || ($code eq 'NO')) { $self->State(Unconnected); return undef; } - if($code =~ /PREAUTH/ ) + if($code eq 'PREAUTH') { $self->State(Authenticated); return $self; } @@ -1327,7 +1343,7 @@ my $litstring = $iBuffer; - while($expected_size > length $iBuffer) + while($expected_size > length $litstring) { if($timeout) { # wait for data from the the IMAP socket. my $rvec = 0; @@ -1346,7 +1362,7 @@ if $fast_io && defined $self->{_fcntl}; my $ret = $self->_sysread($socket - , \$litstring, $expected_size - $litstring, length $litstring); + , \$litstring, $expected_size - length $litstring, length $litstring); $self->_debug("Received ret=$ret and buffer = " . "\n$litstring<END>\nwhile processing LITERAL"); diff -r -u Mail-IMAPClient-2.99_02/lib/Mail/IMAPClient.pod Mail-IMAPClient-2.99_02-NewSocket/lib/Mail/IMAPClient.pod --- Mail-IMAPClient-2.99_02/lib/Mail/IMAPClient.pod 2007-10-26 10:16:30.000000000 +0200 +++ Mail-IMAPClient-2.99_02-NewSocket/lib/Mail/IMAPClient.pod 2007-11-09 15:02:45.293133808 +0100 @@ -119,13 +119,40 @@ of setting an I<Authmechanism> you can just pass the authmechanism as the first argument to AUTHENTICATE. -=item Socket Parameter +=item Socket, RawSocket Parameters -The I<Socket> parameter holds a reference to the socket -connection. Normally this is set for you by the L<connect> method, but +Both parameters hold a reference to the socket connection. +Normally this is set for you by the L<connect> method, but if you are implementing an advanced authentication technique you may choose to set up your own socket connection and then set this parameter -manually, bypassing the B<connect> method completely. +manually, bypassing the B<connect> method completely. This is also +useful if you want to use L<IO::Socket::INET> alternatives, like +L<IO::Socket::SSL>. + +The I<RawSocket> parameter simply records the socket to use for future +operations, without attempting any interaction on it. In this case, you +have to be sure to handle all the preliminar operations and to manually +set the B<Mail::IMAPClient> object in sync with its actual status with +respect to this socket (see below for additional parameters regarding +this, especially the I<State> parameter). + +The I<Socket> parameter, instead, also attempts to carry on preliminar +phases if the conditions apply. If both parameters are present, this +takes the precedence over I<RawSocket>. It is primarily used to +provide an alternative socket for communications, e.g. to use +L<IO::Socket::SSL> instead of L<IO::Socket::INET> used by L<connect> +by default. + + +B< NOTE NOTE NOTE NOTE NOTE NOTE NOTE NOTE NOTE NOTE NOTE NOTE> + +As of version 3 of this module, the I<Socket> parameter has changed +semantics to make it more "DWIM". The I<RawSocket> parameter was +introduced as a replacement for the I<Socket> parameter in older +version. + +B< NOTE NOTE NOTE NOTE NOTE NOTE NOTE NOTE NOTE NOTE NOTE NOTE> + =item State, Server, Proxy, Password, and User Parameters @@ -3229,6 +3256,47 @@ This parameter has no affect on the B<search> method when B<search> is called in a list context. +=head2 RawSocket + +Example: + + $Socket = $imap->RawSocket(); + # or: + $imap->RawSocket($socket_fh); + +The I<RawSocket> method can be used to obtain the socket handle of the +current connection (say, to do I/O on the connection that is not +otherwise supported by B<Mail::IMAPClient>) or to replace the current +socket with a new handle (for instance an SSL handle, see +L<IO::Socket::SSL>, but be sure to see the L<Socket> method as well). + +If you supply a socket handle yourself, either by doing something like: + + $imap=Mail::IMAPClient->new(RawSocket=>$sock, User => ... ); + +or by doing something like: + + $imap=Mail::IMAPClient->new(User => $user, Password => $pass, Server => $host); + # blah blah blah + $imap->RawSocket($ssl); + +then it will be up to you to establish the connection AND to +authenticate, either via the L<login> method, or the fancier +L<authenticate>, or, since you know so much anyway, by just doing raw +I/O against the socket until you're logged in. If you do any of this +then you should also set the L<State> parameter yourself to reflect the +current state of the object (i.e. Connected, Authenticated, etc). + +Note that no operation will be attempted on the socket when this method +is called. In particular, after the TCP connections towards the IMAP +server is established, the protocol mandates the server to send an +initial greeting message, and you will have to explicitly cope with +this message before doing any other operation, e.g. trying to call +L<login>. Caveat emptor. + +For a more DWIM approach to setting the socket see L<Socket>. + + =head2 Readmethod IMAP, BUFFER, LENGTH, OFFSET This parameter, if supplied, should contain a reference to a subroutine @@ -3246,7 +3314,7 @@ Note that this method completely replaces reads from the connection to the server, so if you define one of these then your subroutine will have to actually do the read. It is for things like this that we have -the L<Socket> parameter and eponymous accessor method. +the L<RawSocket>, L<Socket> parameters and eponymous accessor methods. Your I<Readmethod> will probably need to know more than this to do whatever it does. It is recommended that you tuck all other pertinent @@ -3292,6 +3360,14 @@ =head2 Socket +B< NOTE NOTE NOTE NOTE NOTE NOTE NOTE NOTE NOTE NOTE NOTE NOTE> + +The semantics of this method has changed as of version 3 of this module. +If you need the old semantics, you now have to use L<RawSocket>. + +B< NOTE NOTE NOTE NOTE NOTE NOTE NOTE NOTE NOTE NOTE NOTE NOTE> + + Example: $Socket = $imap->Socket(); @@ -3314,14 +3390,48 @@ # blah blah blah $imap->Socket($ssl); -then it will be up to you to establish the connection AND to -authenticate, either via the L<login> method, or the fancier -L<authenticate>, or, since you know so much anyway, by just doing raw -I/O against the socket until you're logged in. If you do any of this -then you should also set the L<State> parameter yourself to reflect the -current state of the object (i.e. Connected, Authenticated, etc). +then it will be up to you to establish the connection, i.e. make sure +that C<$ssl> in the example is a valid and connected socket. + +This method is primarily used to provide a drop-in replacement for +L<IO::Socket::INET>, used by L<connect> by default. In fact, this method +is called by L<connect> itself after having established a suitable +L<IO::Socket::INET> socket connection towards the target server; for +this reason, this method also carries the normal operations associated +with L<connect>, namely: + +=over + +=item * + +read the initial greeting message from the server; + +=item * + +call L<login> if the conditions apply (see L<connect> for details); + +=item * + +leave the I<Mail::IMAPClient> object in a suitable state. + +=back + +For these reasons, the following example will work "out of the box": + + use IO::Socket::SSL; + my $imap = Mail::IMAPClient->new( + User => 'your-username', + Password => 'your-password', + Socket => IO::Socket::SSL->new( + Proto => 'tcp', + PeerAddr => 'some.imap.server', + PeerPort => 993, # IMAP over SSL standard port + ), + ); + +If you need more control over the socket, e.g. you have to implement a fancier +authentication method, see L<RawSocket>. -=cut =head2 Timeout diff -r -u Mail-IMAPClient-2.99_02/t/basic.t Mail-IMAPClient-2.99_02-NewSocket/t/basic.t --- Mail-IMAPClient-2.99_02/t/basic.t 2007-10-26 11:47:03.000000000 +0200 +++ Mail-IMAPClient-2.99_02-NewSocket/t/basic.t 2007-11-09 16:59:20.436710344 +0100 @@ -176,7 +176,7 @@ my $flaghash = $imap->flags(\@hits); my $flagflag = 0; foreach my $v ( values %$flaghash ) -{ $flagflag += grep /\\Deleted/, @$v; +{ $flagflag++ if grep /\\Deleted/, @$v; } cmp_ok($flagflag, '==', scalar @hits); @@ -187,9 +187,8 @@ $flaghash = $imap->flags(\@hits); foreach my $v ( values %$flaghash ) -{ for my $f (@$v) - { $flagflag -= 1 unless grep /\\Deleted/, $f; - } +{ + $flagflag-- unless grep /\\Deleted/, @$v; } cmp_ok($flagflag, '==', 0);
Subject: Re: [rt.cpan.org #30588] Proposed change to Socket method/parameter
Date: Fri, 9 Nov 2007 21:54:10 +0100
To: via RT <bug-Mail-IMAPClient [...] rt.cpan.org>
From: Mark Overmeer <solutions [...] overmeer.net>
* via RT (bug-Mail-IMAPClient@rt.cpan.org) [071109 16:03]: Show quoted text
> Following your suggestion, I attach a new patch that does the following: > * rename the previous "Socket" method to "RawSocket" > * handle a "RawSocket" parameter in the constructor > * change "Socket" method/parameter semantics according to what we're > discussing. In particular, the connect() method ends with a call to > Socket() to complete the initialisation phase and call login() if > applicable. > * changed the documentation where (I thought) it was due. I added > documentation for the new "RawSocket" and changed the documentation for > "Socket", pointing out the changed semantics.
All marvelous changes! Great! Show quoted text
> The attached patch also fixes a couple of bugs in _read_line().
My IMAP provider sends everything at once, so I did not enter the while() loop. Again thanks! Show quoted text
> There > was also a bug in t/basic.t by the way, as you can see from the patch. > Are these bugs a leftover of your overall code revision/rewrite?
Can you explain me why these are bugs? foreach my $v ( values %$flaghash ) -{ $flagflag += grep /\\Deleted/, @$v; +{ $flagflag++ if grep /\\Deleted/, @$v; } cmp_ok($flagflag, '==', scalar @hits); @@ -187,9 +187,8 @@ $flaghash = $imap->flags(\@hits); foreach my $v ( values %$flaghash ) -{ for my $f (@$v) - { $flagflag -= 1 unless grep /\\Deleted/, $f; - } +{ + $flagflag-- unless grep /\\Deleted/, @$v; } In the first case, I increase $flagflags for each Deleted in @$v, in the second, I decrease it for each Deleted. Your rewrite adds one and decreases only one. In my set-up, the tests pass. Show quoted text
> PS: I apologise for not filling a "Subject" line in my first post, I > hate when this happens...
Happens to me often as well. And I did not find a way to correct it. By the way: I did not volutarily took over Mail::IMAPClient maintenance, but had to do it because my MailBox module partly depends on it. There are many users, so at least someone has to apply patches. After a full rewrite (maybe you have noticed) I think the module can have a new life. Of course, I will have introduced a few new bugs. If possible, I would like to find a new maintainer for the new code base... I have more than enough modules already. Feel invited ;-) Thank you very much, so far! -- Regards, MarkOv ------------------------------------------------------------------------ Mark Overmeer MSc MARKOV Solutions drs Mark A.C.J. Overmeer MARKOV Solutions Mark@Overmeer.net solutions@overmeer.net http://Mark.Overmeer.net http://solutions.overmeer.net
Subject: Re: [rt.cpan.org #30588] Proposed change to Socket method/parameter
Date: Sat, 10 Nov 2007 05:36:26 +0100 (CET)
To: bug-Mail-IMAPClient [...] rt.cpan.org
From: "Flavio Poletti" <flavio [...] polettix.it>
Show quoted text
>> There >> was also a bug in t/basic.t by the way, as you can see from the patch. >> Are these bugs a leftover of your overall code revision/rewrite?
> > Can you explain me why these are bugs? > > foreach my $v ( values %$flaghash ) > -{ $flagflag += grep /\\Deleted/, @$v; > +{ $flagflag++ if grep /\\Deleted/, @$v; > } > cmp_ok($flagflag, '==', scalar @hits); > > @@ -187,9 +187,8 @@ > > $flaghash = $imap->flags(\@hits); > foreach my $v ( values %$flaghash ) > -{ for my $f (@$v) > - { $flagflag -= 1 unless grep /\\Deleted/, $f; > - } > +{ > + $flagflag-- unless grep /\\Deleted/, @$v; > } > > In the first case, I increase $flagflags for each Deleted in @$v, > in the second, I decrease it for each Deleted. Your rewrite adds > one and decreases only one. > > In my set-up, the tests pass.
Only the second one is a bug (for me), the first change was actually only to address my paranoic approach. The original code: { $flagflag += grep /\\Deleted/, @$v; added the number of "\\Deleted" found in @$v. I don't really know what's supposed to be there, and if it can ever contain more than one "\\Deleted" given the test's previous setup and, also, what I think that should be in @$v. Anyway, so far, so good. But I then came with a problem in the following test, i.e. the one decreasing $flagflag: { for my $f (@$v) { $flagflag -= 1 unless grep /\\Deleted/, $f; } This is plain wrong for me. In my test, I got a single, empty @$v (see example below), so I don't ever go inside the for to decrease $flagflag. I thought that it could be right, i.e. if the message does not have any flag set, why should @$v contain anything? But again, feel free to be rude in contradicting me, because I don't really know what's supposed to be inside @$v. Anyway, I changed this into: { $flagflag-- unless grep /\\Deleted/, @$v; which made sense: decrease only if "Deleted" is missing from the flags array. This in turn cried for a (paranoid) modification in the $flagflag build, in order to make the increase process match with the new decrease one, which yielded to: { $flagflag++ if grep /\\Deleted/, @$v; Of course, if the '\\Deleted' flag is present only a single time in @$v this is exactly equal to your original code. But I don't give this as a truth and, moreover, I found it more readable and maintainable to have these two processes be based on the same idea. Moreover, if '\\Deleted' is actually present more than one time in the former loop, how can I express its "is lacking more than one time" in the latter? To bake up an example, I added a "use Data::Dumper;" and a couple of 'diag("flaghash:\n" . Dumper($flaghash));' immediately after $flaghash reading. Running through 'prove -vl lib t/basic.t' gives: ... ok 37 - delete hits # flaghash: # $VAR1 = { # '1' => [ # '\\Deleted' # ] # }; ok 38 ok 39 - no hits expected ok 40 - restore messages # flaghash: # $VAR1 = { # '1' => [] # }; ok 41 ... which justifies the increment but not the decrement in the original test code ('1' points to an empty array, so there's no getting into the for loop). I'd be curious to see which flags you get back in your tests, even if I suspect that you're increasing on '\\Deleted' and decreasing on something else, and just getting the correct result by luck ;) Show quoted text
> By the way: I did not volutarily took over Mail::IMAPClient maintenance, > but had to do it because my MailBox module partly depends on it. There > are many users, so at least someone has to apply patches. > > After a full rewrite (maybe you have noticed) I think the module can > have a new life. Of course, I will have introduced a few new bugs. > If possible, I would like to find a new maintainer for the new code > base... I have more than enough modules already. Feel invited ;-)
I'll consider this very carefully, even if I'm using Mail::IMAPClient for something slightly more than a toy, and I never had issues so far. My interest in SSL support has popped up only to play a bit with the new Google IMAP access (see http://www.perlmonks.org/?node_id=649742) -- and this is *definitively* a toy at the moment. Maybe the only reason why I could take this module's maintenance is to get rid of that awful indentation >:-> And now, let the holy war start! :) Of course I'm joking -- "de gustibus non disputandum est", at least when readability is not compromised. You took the module so far, you have the right to adapt it to your coding standards. Show quoted text
> Thank you very much, so far!
It's a pleasure to work with someone constructively responsive :) Cheers, Flavio.
Subject: Re: [rt.cpan.org #30588] Proposed change to Socket method/parameter
Date: Sat, 10 Nov 2007 20:57:41 +0100
To: Flavio Poletti via RT <bug-Mail-IMAPClient [...] rt.cpan.org>
From: Mark Overmeer <mark [...] overmeer.net>
* Flavio Poletti via RT (bug-Mail-IMAPClient@rt.cpan.org) [071110 04:27]: Show quoted text
> Only the second one is a bug (for me), the first change was actually only > to address my paranoic approach. The original code:
Your are correct, (of course) The second test was wroint. Show quoted text
> added the number of "\\Deleted" found in @$v. I don't really know what's > supposed to be there, and if it can ever contain more than one "\\Deleted" > given the test's previous setup and, also, what I think that should be in > @$v. Anyway, so far, so good.
Yes, you could find more than one... but not if you check only one message... I did not try to be smart in translating the messages. The follow test-script works as expected #!/usr/bin/perl use warnings; use strict; my $flagflag = 0; my %flaghash = ( 1 => ['\\Deleted'], 2 => ['\\Deleted'] ); foreach my $v (values %flaghash) { $flagflag++ if grep /\\Deleted/, @$v; } print "1st $flagflag\n"; %flaghash = (1 => [], 2 => ['\\Deleted']); foreach my $v (values %flaghash) { $flagflag -= 1 unless grep /\\Deleted/, @$v; } print "2st $flagflag\n"; Show quoted text
> > By the way: I did not voluntarily took over Mail::IMAPClient maintenance,
Show quoted text
> I'll consider this very carefully, even if I'm using Mail::IMAPClient for > something slightly more than a toy, and I never had issues so far.
I never use IMAP, so you win ;-) Show quoted text
> Of course I'm joking -- "de gustibus non disputandum est", at least when > readability is not compromised. You took the module so far, you have the > right to adapt it to your coding standards.
The style is easier to understand, is my experience as Perl teacher. And, at least it is an attempt to be consequent. I will release 2.99_04, with all your fixes in a moment. Start getting somewhere, thanks to help. -- Regards, MarkOv ------------------------------------------------------------------------ Mark Overmeer MSc MARKOV Solutions Mark@Overmeer.net solutions@overmeer.net http://Mark.Overmeer.net http://solutions.overmeer.net
Subject: rawsocket/socket
probably solved