1. my role IO::Socket {
  2. has $!PIO;
  3. has Str $.encoding = 'utf8';
  4. has $.nl-in is rw = ["\n", "\r\n"];
  5. has Str:D $.nl-out is rw = "\n";
  6. has Rakudo::Internals::VMBackedDecoder $!decoder;
  7. method !ensure-decoder(--> Nil) {
  8. unless $!decoder.DEFINITE {
  9. $!decoder := Rakudo::Internals::VMBackedDecoder.new($!encoding);
  10. $!decoder.set-line-separators($!nl-in);
  11. }
  12. }
  13. # The if bin is true, will return Buf, Str otherwise
  14. method recv(Cool $limit? is copy, :$bin) {
  15. fail('Socket not available') unless $!PIO;
  16. $limit = 65535 if !$limit.DEFINITE || $limit === Inf;
  17. if $bin {
  18. nqp::readfh($!PIO, nqp::decont(buf8.new), $limit)
  19. }
  20. else {
  21. self!ensure-decoder();
  22. my $result = $!decoder.consume-exactly-chars($limit);
  23. without $result {
  24. $!decoder.add-bytes(nqp::readfh($!PIO, nqp::decont(buf8.new), 65535));
  25. $result = $!decoder.consume-exactly-chars($limit);
  26. without $result {
  27. $result = $!decoder.consume-all-chars();
  28. }
  29. }
  30. $result
  31. }
  32. }
  33. method read(IO::Socket:D: Int(Cool) $bufsize) {
  34. fail('Socket not available') unless $!PIO;
  35. my int $toread = $bufsize;
  36. my $res := nqp::readfh($!PIO,buf8.new,$toread);
  37. while nqp::elems($res) < $toread {
  38. my $buf := nqp::readfh($!PIO,buf8.new,$toread - nqp::elems($res));
  39. nqp::elems($buf)
  40. ?? $res.append($buf)
  41. !! return $res
  42. }
  43. $res
  44. }
  45. method nl-in is rw {
  46. Proxy.new(
  47. FETCH => { $!nl-in },
  48. STORE => -> $, $nl-in {
  49. $!nl-in = $nl-in;
  50. with $!decoder {
  51. .set-line-separators($!nl-in.list);
  52. }
  53. $nl-in
  54. }
  55. )
  56. }
  57. method get() {
  58. self!ensure-decoder();
  59. my Str $line = $!decoder.consume-line-chars(:chomp);
  60. if $line.DEFINITE {
  61. $line
  62. }
  63. else {
  64. loop {
  65. my $read = nqp::readfh($!PIO, nqp::decont(buf8.new), 65535);
  66. $!decoder.add-bytes($read);
  67. $line = $!decoder.consume-line-chars(:chomp);
  68. last if $line.DEFINITE;
  69. if $read == 0 {
  70. $line = $!decoder.consume-line-chars(:chomp, :eof);
  71. last;
  72. }
  73. }
  74. $line.DEFINITE ?? $line !! Nil
  75. }
  76. }
  77. method lines() {
  78. gather while (my $line = self.get()).DEFINITE {
  79. take $line;
  80. }
  81. }
  82. method print(Str(Cool) $string --> True) {
  83. self.write($string.encode($!encoding));
  84. }
  85. method put(Str(Cool) $string --> True) {
  86. self.print($string ~ $!nl-out);
  87. }
  88. method write(Blob:D $buf --> True) {
  89. fail('Socket not available') unless $!PIO;
  90. nqp::writefh($!PIO, nqp::decont($buf));
  91. }
  92. method close(--> True) {
  93. fail("Not connected!") unless $!PIO;
  94. nqp::closefh($!PIO);
  95. $!PIO := nqp::null;
  96. }
  97. method native-descriptor(::?CLASS:D:) {
  98. nqp::filenofh($!PIO)
  99. }
  100. }