# Porting a really Ruby IO.select use case into Crystal

**URL:** https://forum.crystal-lang.org/t/porting-a-really-ruby-io-select-use-case-into-crystal/5080
**Category:** Help & Support
**Created:** [November 5, 2022, 1:23pm UTC](https://forum.crystal-lang.org/t/porting-a-really-ruby-io-select-use-case-into-crystal/5080 "2022-11-05T13:23:46Z")
**Posts on this page:** 6
**Page:** 1

<div class="post-metadata">

### Author: ![zw963](https://yyz2.discourse-cdn.com/flex036/user_avatar/forum.crystal-lang.org/zw963/32/1623_2.png) [@zw963](https://forum.crystal-lang.org/u/zw963)
#### Post date: [November 5, 2022, 1:23pm UTC](https://forum.crystal-lang.org/t/porting-a-really-ruby-io-select-use-case-into-crystal/5080/1 "2022-11-05T13:23:46Z")

</div>

i am current porting a ruby gem like [Foreman](https://github.com/ddollar/foreman) but things are designed to run in both foreground/background into Crystal, I am quite ensure it is doable, although there are many challenges.

Following is one about `IO.select`, i am not a expect of it, in fact, manipulate it directly rarely, I need help.

The original ruby version code is [here](https://github.com/zw963/procodile_cr/blob/7fb5112e727f720b7a51c987e286921b6b481ba4/src/procodile/tcp_proxy.cr#L39-L71), following is the copy.

```ruby
def listen
  loop do
    # IO.select IOs, timeout 30 seconds
    io = IO.select([@sp_reader] + @listeners.keys, nil, nil, 30)

    if io && io.first
      io.first.each do |io|
        if io == @sp_reader
          io.read_nonblock(999)
          next
        end

        Thread.new(io) do |io|
          handle_client(client: io.accept, server: io)
        end
      end
    end

    @stopped_processes.reject do |process|
      if io = @listeners.key(process)
        Procodile.log nil, "proxy", "Stopped proxy listener for #{process.name}"
        io.close
        @listeners.delete(io)
      end

      true
    end
  end
rescue e
  Procodile.log nil, "proxy", "Exception: #{e.class}: #{e.message}"
  Procodile.log nil, "proxy", e.backtrace[0, 5].join("\n")
end

```

Now, i want to port to Crystal, because the IO.select was removed, as describe by [this](https://github.com/crystal-lang/crystal/pull/4392#issuecomment-300141926),

> [@](#):
>
> Anybody coming here and lacking support for IO.select,  
> you should spawn fibers to read/write to each IO,  
> and let Crystal switch fibers as available/required.

But, i don’t sure how to handle this, following is a attempt.

```crystal
def listen
  sleep_chan = Channel(Nil).new
  sp_reader_chan = Channel(Nil).new
  listener_chan = Channel(Nil).new

  spawn do
    loop do
      sleep 30
      sleep_chan.send nil
    end
  end

  spawn do
    loop do
      @sp_reader.read(Bytes.new(999))
      sp_reader_chan.send nil
    end
  end

  @listeners.keys.each do |io|
    spawn do
      loop do
        handle_client(client: io.accept, server: io)
        listener_chan.send nil
      end
    end
  end

  loop do
    select
    when sp_reader_chan.receive
    when listener_chan.receive
    when sleep_chan.receive
    end

    @stopped_processes.reject do |process|
      if io = @listeners.key(process)
        Procodile.log nil, "proxy", "Stopped proxy listener for #{process.name}"
        io.close
        @listeners.delete(io)
      end

      true
    end
  end
end

```

Please help point out the issue, incorrect usage.

Hopefully more and more Ruby code can be rewritten in Crystal.

---

<div class="post-metadata">

### Author: ![naqvis](https://yyz2.discourse-cdn.com/flex036/user_avatar/forum.crystal-lang.org/naqvis/32/906_2.png) [@naqvis](https://forum.crystal-lang.org/u/naqvis)
#### Post date: [November 5, 2022, 2:07pm UTC](https://forum.crystal-lang.org/t/porting-a-really-ruby-io-select-use-case-into-crystal/5080/2 "2022-11-05T14:07:02Z")

</div>

> [@zw963](#):
>
> i am current porting a ruby gem like [Foreman](https://github.com/ddollar/foreman) but things are designed to run in both

On Github repo of your cited gem, it shows that there is a Crystal implementation in place. Have you looked into that? [GitHub - arktisklada/crank: Foreman port to crystal.](https://github.com/arktisklada/crank)

---

<div class="post-metadata">

### Author: ![zw963](https://yyz2.discourse-cdn.com/flex036/user_avatar/forum.crystal-lang.org/zw963/32/1623_2.png) [@zw963](https://forum.crystal-lang.org/u/zw963)
#### Post date: [November 5, 2022, 2:34pm UTC](https://forum.crystal-lang.org/t/porting-a-really-ruby-io-select-use-case-into-crystal/5080/3 "2022-11-05T14:34:34Z")

</div>

Cool, thanks.

i don’t know this shard before, i will refer to it when i have issue, i test crank shards just now, it not work anymore because crystal version is too old, i have to fix it before run it.

I personal use procodile on my projects, so, i want to rewrite it, The main purpose is to improve my Crystal skills more quickly.

---

<div class="post-metadata">

### Author: ![zw963](https://yyz2.discourse-cdn.com/flex036/user_avatar/forum.crystal-lang.org/zw963/32/1623_2.png) [@zw963](https://forum.crystal-lang.org/u/zw963)
#### Post date: [November 5, 2022, 5:03pm UTC](https://forum.crystal-lang.org/t/porting-a-really-ruby-io-select-use-case-into-crystal/5080/4 "2022-11-05T17:03:11Z")

</div>

@naqvis , thanks very much for help, crank starts work now.

> **[GitHub - zw963/crank: Foreman port to crystal.](https://github.com/zw963/crank)**
>
> Foreman port to crystal. Contribute to zw963/crank development by creating an account on GitHub.

Procodile is far feature rich than crank, but, i will refer to its implementation.

---

<div class="post-metadata">

### Author: ![mdwagner](https://yyz2.discourse-cdn.com/flex036/user_avatar/forum.crystal-lang.org/mdwagner/32/1077_2.png) [@mdwagner](https://forum.crystal-lang.org/u/mdwagner)
#### Post date: [November 6, 2022, 1:40am UTC](https://forum.crystal-lang.org/t/porting-a-really-ruby-io-select-use-case-into-crystal/5080/5 "2022-11-06T01:40:34Z")

</div>

Have you heard of Nox before (used by Lucky)? [GitHub - matthewmcgarvey/nox: Procfile-based process manager written in Crystal](https://github.com/matthewmcgarvey/nox)

---

<div class="post-metadata">

### Author: ![zw963](https://yyz2.discourse-cdn.com/flex036/user_avatar/forum.crystal-lang.org/zw963/32/1623_2.png) [@zw963](https://forum.crystal-lang.org/u/zw963)
#### Post date: [November 6, 2022, 3:21am UTC](https://forum.crystal-lang.org/t/porting-a-really-ruby-io-select-use-case-into-crystal/5080/6 "2022-11-06T03:21:56Z")

</div>

Oops, i knew it, but i forget it before you mention it, thanks
