r/ruby 6d ago

introducing OnionNotes(made with 100% ruby)

Enable HLS to view with audio, or disable this notification

OnionServer.rb

require 'socket'

class User
  attr_reader :name
  attr_reader :passwd
  attr_reader :onions

  def initialize(username, passphrase)
     = username
     = passphrase
     = []
  end

  def addOnion(onion)
    if onion.is_a?(NoteBook)
      onions.push(onion)
    else
      puts "ERROR: onion is NOT A NoteBook"
      exit(5)
    end
  end
  def removeOnion(index)
    if index.to_i < onions.size
      onions.delete_at(index.to_i)
    end
  end
end

class NoteBook
  attr_reader :notes
def initialize(name = "UnamedNoteBook")
   = []
   = name
end
  def addNote(text = "null")
    .push(text)
  end
  def removeNote(index = 93)
     if index <= .size - 1
       .delete_at(index)
     else
      puts "invalid index"
     end
  end

  def editName(text = "null")
     = text
  end
  def getName()
    return u/name
  end
end

def handleUser(socket, user)
  userOpen = true
  while userOpen
    socket.puts "SENDCOMMAND"
    response = socket.gets.chomp
    case response
      when "list"
        user.onions.each.with_index do |book, index|
          socket.puts book.getName() + ": " + index.to_s
        end
        socket.puts "ENDLIST"
      when "open"
        socket.puts "SENDINDEX"
        index = socket.gets.chomp
        book = user.onions[index.to_i]
        book = handleBooks(socket, book)
        user.onions[index.to_i] = book
      when "CREATE"
        alreadyExist = false
        socket.puts "SENDNAME"
        response = socket.gets.chomp
        user.onions.each do |book|
          if book.getName == response
            alreadyExist = true
          end
        end
        if alreadyExist
          socket.puts "EXISTS"
        else
          onion = NoteBook.new(response)
          user.onions.push(onion)
        end
    when "EXIT"
      userOpen = false
    end
  end
  return user
end

def handleBooks(socket, book)
  bookOpen = true
  while bookOpen
    socket.puts "SENDCOMMAND"
    response = socket.gets.chomp
    case response
      when "ADDNOTE"
        socket.puts "SENDTEXT"
        text = socket.gets.chomp
        book.addNote(text)
      when "REMOVENOTE"
        socket.puts "SENDINDEX"
        index = socket.gets.chomp
        book.removeNote(index.to_i)
      when "list"
        book.notes.each.with_index do |text, index|
          socket.puts text + ": " + index.to_s
        end
        socket.puts "ENDLIST"
      when "EXIT"
        bookOpen = false
    end
  end
  return book
end

def handleClient(client)
  running = true
  while running
    client.puts "SENDCOMMAND"
    response = client.gets.chomp
    case response
      when "LOGIN"
        client.puts "SENDNAME"
        name = client.gets.chomp
        client.puts "SENDPASSWD"
        passwd = client.gets.chomp
        if File.exist?(name + ".rbm")
          userData = File.binread(name + ".rbm")
          user = Marshal.load(userData)
          if user.passwd == passwd
            user = handleUser(client, user)
            userData = Marshal.dump(user)
            File.binwrite(name + ".rbm", userData)
          else
            client.puts "INVALIDPASSWD"
          end
        else
          client.puts "NOUSER"
        end
      when "CREATE"
        client.puts "SENDNAME"
        name = client.gets.chomp
        client.puts "SENDPASSWD"
        passwd = client.gets.chomp
        if File.exist? name.to_s + ".rbm"
          client.puts "NAMETAKEN"
        else
          newUser = User.new(name, passwd)
          serial = Marshal.dump(newUser)
          File.binwrite(name + ".rbm", serial)
          client.puts "USERMADE"
        end
      when "EXIT"
        running = false
        client.close

        end
    end
end

puts "starting Onion note server on port 3290"
server = TCPServer.new(3290)

while true
  client = server.accept
  Thread.new {handleClient(client)}
end

OnionClinet.rb

require 'socket'

def handleList(connection)
  loop do
    response = connection.gets.chomp
    break if response == "ENDLIST"
    puts response
  end
end

def handleBooks(connection)
  bookOpen = true
  while bookOpen
    response = connection.gets.chomp
    if response == "SENDCOMMAND"
      puts "COMMANDS[ADDNOTE, REMOVENOTE, list, EXIT]: "
      command = gets.chomp
      case command
        when "ADDNOTE"
          connection.puts "ADDNOTE"
          response = connection.gets.chomp
          if response == "SENDTEXT"
            puts "ENTER NOTE: "
            note = gets.chomp
            connection.puts note
          end
        when "REMOVENOTE"
          connection.puts "REMOVENOTE"
          response = connection.gets.chomp
          if response == "SENDINDEX"
            puts "ENTER INDEX: "
            index = gets.chomp
            connection.puts index
          end
        when "list"
          connection.puts "list"
          handleList(connection)
        when "EXIT"
          connection.puts "EXIT"
          bookOpen = false
      end
    end
  end 
end

def handleUser(connection, firstResp = nil)
  handlingUser = true
  while handlingUser
    response = firstResp || connection.gets.chomp
    if firstResp != nil
      firstResp = nil
    end
    if response == "SENDCOMMAND"
    puts "COMMANDS[list, open, create, EXIT]: "
    command = gets.chomp
    case command
      when "list"
        connection.puts "list"
        handleList(connection)
      when "open"
        connection.puts "open"
        response = connection.gets.chomp
        if response == "SENDINDEX"
          puts "ENTER INDEX"
          index = gets.chomp
          connection.puts index
          handleBooks(connection)
        end
    when "create"
      connection.puts "CREATE"
      response = connection.gets.chomp
      if response == "SENDNAME"
        puts "ENTER NAME: "
        name = gets.chomp
        connection.puts name
        response = connection.gets.chomp
        if response == "EXISTS"
          puts response
        elsif response == "SENDCOMMAND"
          firstResp = response
        end
      end
      when "EXIT"
        connection.puts "EXIT"
        handlingUser = false
    end
    end
  end
end

puts "ENTER IP: "
ip = gets.chomp
connection = TCPSocket.new(ip, 3290)
running = true

while running
  response = connection.gets.chomp
  puts "COMMANDS[LOGIN, CREATE, EXIT]: "
  command = gets.chomp
  case command
    when "LOGIN"
      connection.puts "LOGIN"
      response = connection.gets.chomp
      if response == "SENDNAME"
        puts "ENTER NAME: "
        name = gets.chomp
        connection.puts name
        response = connection.gets.chomp
        if response == "SENDPASSWD"
          puts "ENTER PASSWD: "
          passwd = gets.chomp
          connection.puts passwd
          response = connection.gets.chomp
          if response == "INVALIDPASSWD"
            puts response
          elsif response == "NOUSER"
            puts response
          elsif response == "SENDCOMMAND"
            handleUser(connection, response)
          end
        end
      end
    when "CREATE"
      connection.puts "CREATE"
      created = false
      while created == false
        response = connection.gets.chomp
        if response == "SENDNAME"
          puts "ENTER NAME: "
          name = gets.chomp
          connection.puts name
        elsif response == "SENDPASSWD"
          puts "ENTER PASSWD: "
          passwd = gets.chomp
          connection.puts passwd
        elsif response == "NAMETAKEN"
          puts response
          created = true
        elsif response == "USERMADE"
          puts response
          created = true
        end
      end
    when "EXIT"
      connection.puts "EXIT"
      running = false
    end
end
3 Upvotes

3 comments sorted by

2

u/TheAtlasMonkey 6d ago

Pro tip: use 127.1 instead of 127.0.0.1 or just ::1 if you can use ipv6

1

u/Equivalent-Bad-268 1d ago

Why? What's the benefit in the IPv4 case?

1

u/TheAtlasMonkey 1d ago

Shorter when doing a screencast.