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