I have a rails app (5.2.2.1) and I want to add a feature to support a external legacy system which it’s need to connect to socket with his own protocol.
I did a reverse engineering to this protocol, and I want to use it with rails app benefits like models.
In my case I added this code to config/initializers/entrance_lathes.rb:
require 'socket'
Thread.new do
TCPServer.open(9999) do |srv|
loop do
Thread.start(srv.accept) do |cli|
line = cli.gets(chomp: true)
id, action, args = line.split
# ... Query with ActiveRecord to logic
# Finishing connection
cli.puts "See you soon #{id}!"
cli.flush
cli.close
end
end
end
end.join
Of course, before any deployment, I wrap this code into clases.
Questions;
It’s a good practice add a TCPServer inside rails app?
There are a better way or solution to do this?
How to in development environment if I code change, how is to do reloaded, close, and open again tcpserver?
I can’t help you but it does sound interesting. I assume you would need to hook either into the web server (puma or similar) and maybe make some workarounds around rack. Will the protocol be using a classic request-response system or will the TCP stream stay open? If it stays open, you might be able to hook into Action Cable.
Sometimes I wondered if rails in combination with action cable could be used as a ssh command line tui backend.
Edit: Maybe you can write an intermediate software in a separate process which allows the legacy system to connect. This intermediate layer will then talk via HTTP to the rails server. This would provide you with an easier separation of concern and might avoid you some performance troubles within the rails web process.
It depends on your deployment setup, but I would lean toward creating a separate ruby project that starts the TCP server and manages the protocol, and loads and uses Rails as necessary.
I have a ruby project that is run as a command-line program, either externally or from a request to the Rails app. Here’s some sample code to load the rails app into that external ruby program, after which the rails app models can be accessed same as in the rails app itself.
# load rails environment so I can use ActiveRecord models for data access
if defined?(Rails)
puts("Rails is already loaded")
else
puts("Rails not previously loaded...attempting to load from #{@config[:rails_dir]}...")
ENV['RAILS_ENV'] = @args[:environment]
Dir.chdir(@config[:rails_dir]) do
require "#{@config[:rails_dir]}/config/environment.rb"
end
end
exit 5 unless defined?(Rails)
Since this program is a “run and done” I don’t need to worry about reloading the Rails app in development mode. However, you could potentially check your environment and just call Rails.application.reloader.reload! in same way that makes sense for your custom protocol.