Skip to content

Instantly share code, notes, and snippets.

@ytnk531
Created September 24, 2019 17:53
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save ytnk531/4be3ba9a72da2fe024ce9c98508562f8 to your computer and use it in GitHub Desktop.
Save ytnk531/4be3ba9a72da2fe024ce9c98508562f8 to your computer and use it in GitHub Desktop.
# frozen_string_literal: true
require 'fiber'
# Manage packet.
class Packets
def initialize
@packets = []
end
def add(packet)
@packets << packet
end
def delete(packet)
@packets.delete(packet)
end
def find_by_dest(node)
@packets.select { |packet| packet.dest == node }.first
end
def for?(node)
@packets.select { |packet| packet.dest == node }.first
end
end
# Network.
# This presents behaviroes of network seen from layer 5.
class Network
def initialize
@packets = Packets.new
@blocked_nodes = {}
end
def send_packet(packet)
@blocked_nodes.key?(packet.dest)
@packets.add(packet)
return unless (fiber = @blocked_nodes[packet.dest.id])
fiber.resume(packet)
end
def receive(node)
unless @packets.for?(node)
schedule_receive(node.id, Fiber.current)
Fiber.yield
end
packet = @packets.find_by_dest(node)
@packets.delete(packet)
end
def schedule_receive(id, fiber)
@blocked_nodes.merge!(id => fiber)
end
end
# Packet.
class Packet
attr_accessor :dest, :sender, :data
def initialize(dest: nil, sender: nil, data: nil)
@dest = dest
@sender = sender
@data = data
end
def to_s
"dest: #{@dest.id}, sender: #{@sender.id}, data: #{@data}"
end
end
# Node.
class Node
@id_counter = 0
attr_reader :id
def self.new_id
@id_counter += 1
end
def initialize(network)
@network = network
@id = self.class.new_id
end
def send_to(node, data)
@network.send_packet(Packet.new(dest: node, sender: self, data: data))
end
def receive
@network.receive(self)
end
def execute(&block)
Fiber.new do
block.call(self)
end.resume
end
def print_log(message)
puts "node:#{@id} #{message}"
end
end
network = Network.new
n1 = Node.new(network)
n2 = Node.new(network)
n3 = Node.new(network)
n1.execute do |node|
node.send_to(n2, 'Hello.')
packet = node.receive
node.print_log("received packet: #{packet}")
end
n2.execute do |node|
packet = node.receive
node.print_log("received packet: #{packet}")
node.send_to(n1, "I received your message. You said #{packet.data}")
packet = node.receive
node.print_log(packet)
end
n3.execute do |node|
node.send_to(n2, "I'm node3")
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment