Skip to content

Instantly share code, notes, and snippets.

@ytnk531
Last active September 24, 2019 17:57
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/ea8c4f8ba28e8437d7ec0d8360100d76 to your computer and use it in GitHub Desktop.
Save ytnk531/ea8c4f8ba28e8437d7ec0d8360100d76 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
@ytnk531
Copy link
Author

ytnk531 commented Sep 24, 2019

Decorator pattern may be good for invoking methods for managing fibers.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment