carbonmu 0.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +7 -0
 - data/.gitignore +3 -0
 - data/.rspec +2 -0
 - data/.ruby-gemset +1 -0
 - data/.ruby-version +1 -0
 - data/.travis.yml +14 -0
 - data/Gemfile +3 -0
 - data/Gemfile.lock +161 -0
 - data/Guardfile +50 -0
 - data/LICENSE.txt +21 -0
 - data/README.md +66 -0
 - data/Rakefile +10 -0
 - data/carbonmu.gemspec +64 -0
 - data/config/i18n-tasks.yml +89 -0
 - data/config/locales/en.yml +6 -0
 - data/config/locales/nl.yml +6 -0
 - data/console +9 -0
 - data/doc/architecture.png +0 -0
 - data/lib/carbonmu.rb +42 -0
 - data/lib/commands/locale_command.rb +12 -0
 - data/lib/commands/ping_command.rb +9 -0
 - data/lib/commands/reboot_command.rb +9 -0
 - data/lib/commands/say_command.rb +10 -0
 - data/lib/commands/unknown_command.rb +7 -0
 - data/lib/core/command.rb +26 -0
 - data/lib/core/command_context.rb +12 -0
 - data/lib/core/configuration.rb +22 -0
 - data/lib/core/connection.rb +19 -0
 - data/lib/core/internationalization.rb +16 -0
 - data/lib/core/parser.rb +29 -0
 - data/lib/core/server.rb +118 -0
 - data/lib/core/server_supervision_group.rb +5 -0
 - data/lib/core_ext/match_data.rb +7 -0
 - data/lib/core_ext/string.rb +5 -0
 - data/lib/edge_router/edge_connection.rb +39 -0
 - data/lib/edge_router/edge_router.rb +104 -0
 - data/lib/edge_router/edge_router_supervision_group.rb +5 -0
 - data/lib/edge_router/telnet_connection.rb +35 -0
 - data/lib/edge_router/telnet_receptor.rb +30 -0
 - data/lib/errors.rb +4 -0
 - data/lib/game_objects/container.rb +10 -0
 - data/lib/game_objects/exit.rb +8 -0
 - data/lib/game_objects/game_object.rb +13 -0
 - data/lib/game_objects/movable.rb +12 -0
 - data/lib/game_objects/player.rb +17 -0
 - data/lib/game_objects/room.rb +16 -0
 - data/lib/game_objects/thing.rb +7 -0
 - data/lib/interactions/notify.rb +11 -0
 - data/lib/interactions/reboot.rb +8 -0
 - data/lib/ipc/carbon_ipc_socket.rb +21 -0
 - data/lib/ipc/ipc_message.rb +54 -0
 - data/lib/ipc/read_socket.rb +18 -0
 - data/lib/ipc/write_socket.rb +12 -0
 - data/lib/version.rb +7 -0
 - data/mongoid.yml +12 -0
 - data/spec/carbonmu_spec.rb +14 -0
 - data/spec/i18n_spec.rb +18 -0
 - data/spec/lib/commands/say_command_spec.rb +11 -0
 - data/spec/lib/core/command_context_spec.rb +16 -0
 - data/spec/lib/core/command_spec.rb +37 -0
 - data/spec/lib/core/configuration_spec.rb +37 -0
 - data/spec/lib/core/connection_spec.rb +46 -0
 - data/spec/lib/core/internationalization_spec.rb +24 -0
 - data/spec/lib/core/parser_spec.rb +30 -0
 - data/spec/lib/core/server_spec.rb +35 -0
 - data/spec/lib/edge_router/edge_connection_spec.rb +9 -0
 - data/spec/lib/game_objects/container_spec.rb +9 -0
 - data/spec/lib/game_objects/exit_spec.rb +7 -0
 - data/spec/lib/game_objects/game_object_spec.rb +12 -0
 - data/spec/lib/game_objects/movable_spec.rb +9 -0
 - data/spec/lib/game_objects/player_spec.rb +24 -0
 - data/spec/lib/game_objects/room_spec.rb +20 -0
 - data/spec/lib/game_objects/thing_spec.rb +7 -0
 - data/spec/lib/interactions/notify_spec.rb +26 -0
 - data/spec/lib/interactions/reboot_spec.rb +9 -0
 - data/spec/lib/ipc/carbon_ipc_socket_spec.rb +12 -0
 - data/spec/lib/ipc/ipc_message_spec.rb +39 -0
 - data/spec/lib/ipc/read_socket_spec.bak +51 -0
 - data/spec/lib/ipc/write_socket_spec.bak +25 -0
 - data/spec/spec_helper.rb +118 -0
 - data/spec/support/helpers.rb +15 -0
 - data/spec/support/matchers/be_boolean.rb +5 -0
 - data/spec/support/shared_examples/carbon_ipc_socket.rb +3 -0
 - data/spec/support/shared_examples/container.rb +3 -0
 - data/spec/support/shared_examples/game_object.rb +6 -0
 - data/spec/support/shared_examples/movable.rb +4 -0
 - data/start +5 -0
 - data/start-server-only +8 -0
 - metadata +416 -0
 
    
        data/console
    ADDED
    
    
| 
         Binary file 
     | 
    
        data/lib/carbonmu.rb
    ADDED
    
    | 
         @@ -0,0 +1,42 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            require 'rubygems'
         
     | 
| 
      
 2 
     | 
    
         
            +
            require 'bundler/setup'
         
     | 
| 
      
 3 
     | 
    
         
            +
             
     | 
| 
      
 4 
     | 
    
         
            +
            require 'require_all'
         
     | 
| 
      
 5 
     | 
    
         
            +
            require 'colorize' # An exception to our require-where-used rule, since it's likely to be used many places.
         
     | 
| 
      
 6 
     | 
    
         
            +
            require_all 'lib'
         
     | 
| 
      
 7 
     | 
    
         
            +
             
     | 
| 
      
 8 
     | 
    
         
            +
            Celluloid::ZMQ.init
         
     | 
| 
      
 9 
     | 
    
         
            +
             
     | 
| 
      
 10 
     | 
    
         
            +
            module CarbonMU
         
     | 
| 
      
 11 
     | 
    
         
            +
              class << self
         
     | 
| 
      
 12 
     | 
    
         
            +
                attr_accessor :configuration
         
     | 
| 
      
 13 
     | 
    
         
            +
                attr_accessor :edge_router_receive_port
         
     | 
| 
      
 14 
     | 
    
         
            +
                attr_accessor :server
         
     | 
| 
      
 15 
     | 
    
         
            +
              end
         
     | 
| 
      
 16 
     | 
    
         
            +
              self.configuration = Configuration.new
         
     | 
| 
      
 17 
     | 
    
         
            +
             
     | 
| 
      
 18 
     | 
    
         
            +
              def self.configure
         
     | 
| 
      
 19 
     | 
    
         
            +
                yield self.configuration
         
     | 
| 
      
 20 
     | 
    
         
            +
              end
         
     | 
| 
      
 21 
     | 
    
         
            +
             
     | 
| 
      
 22 
     | 
    
         
            +
              def self.start
         
     | 
| 
      
 23 
     | 
    
         
            +
                EdgeRouterSupervisionGroup.run
         
     | 
| 
      
 24 
     | 
    
         
            +
              end
         
     | 
| 
      
 25 
     | 
    
         
            +
             
     | 
| 
      
 26 
     | 
    
         
            +
              def self.start_in_background
         
     | 
| 
      
 27 
     | 
    
         
            +
                EdgeRouterSupervisionGroup.run!
         
     | 
| 
      
 28 
     | 
    
         
            +
              end
         
     | 
| 
      
 29 
     | 
    
         
            +
             
     | 
| 
      
 30 
     | 
    
         
            +
              def self.start_server
         
     | 
| 
      
 31 
     | 
    
         
            +
                ServerSupervisionGroup.run
         
     | 
| 
      
 32 
     | 
    
         
            +
              end
         
     | 
| 
      
 33 
     | 
    
         
            +
             
     | 
| 
      
 34 
     | 
    
         
            +
              def self.start_server_in_background
         
     | 
| 
      
 35 
     | 
    
         
            +
                ServerSupervisionGroup.run!
         
     | 
| 
      
 36 
     | 
    
         
            +
              end
         
     | 
| 
      
 37 
     | 
    
         
            +
             
     | 
| 
      
 38 
     | 
    
         
            +
              def self.t(str, *opts)
         
     | 
| 
      
 39 
     | 
    
         
            +
                CarbonMU::Internationalization.translate(str, opts)
         
     | 
| 
      
 40 
     | 
    
         
            +
              end
         
     | 
| 
      
 41 
     | 
    
         
            +
            end
         
     | 
| 
      
 42 
     | 
    
         
            +
             
     | 
| 
         @@ -0,0 +1,12 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            # TODO TEMP
         
     | 
| 
      
 2 
     | 
    
         
            +
            module CarbonMU
         
     | 
| 
      
 3 
     | 
    
         
            +
              class LocaleCommand < Command
         
     | 
| 
      
 4 
     | 
    
         
            +
                syntax /^locale (?<locale>.*)/
         
     | 
| 
      
 5 
     | 
    
         
            +
                syntax /^do (?<text>.*)/
         
     | 
| 
      
 6 
     | 
    
         
            +
             
     | 
| 
      
 7 
     | 
    
         
            +
                def execute
         
     | 
| 
      
 8 
     | 
    
         
            +
                  @context.enacting_connection.locale = @params[:locale]
         
     | 
| 
      
 9 
     | 
    
         
            +
                  Notify.one(@context.enacting_connection, "Locale changed to #{@params[:locale]}.")
         
     | 
| 
      
 10 
     | 
    
         
            +
                end
         
     | 
| 
      
 11 
     | 
    
         
            +
              end
         
     | 
| 
      
 12 
     | 
    
         
            +
            end
         
     | 
    
        data/lib/core/command.rb
    ADDED
    
    | 
         @@ -0,0 +1,26 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            module CarbonMU
         
     | 
| 
      
 2 
     | 
    
         
            +
              class Command
         
     | 
| 
      
 3 
     | 
    
         
            +
                class << self
         
     | 
| 
      
 4 
     | 
    
         
            +
                  def syntax(value)
         
     | 
| 
      
 5 
     | 
    
         
            +
                    @syntaxes ||= []
         
     | 
| 
      
 6 
     | 
    
         
            +
                    @syntaxes << value
         
     | 
| 
      
 7 
     | 
    
         
            +
                    Parser.register_syntax(value, self)
         
     | 
| 
      
 8 
     | 
    
         
            +
                  end
         
     | 
| 
      
 9 
     | 
    
         
            +
             
     | 
| 
      
 10 
     | 
    
         
            +
                  def syntaxes
         
     | 
| 
      
 11 
     | 
    
         
            +
                    @syntaxes
         
     | 
| 
      
 12 
     | 
    
         
            +
                  end
         
     | 
| 
      
 13 
     | 
    
         
            +
                end
         
     | 
| 
      
 14 
     | 
    
         
            +
             
     | 
| 
      
 15 
     | 
    
         
            +
                attr_reader :context
         
     | 
| 
      
 16 
     | 
    
         
            +
             
     | 
| 
      
 17 
     | 
    
         
            +
                def initialize(context)
         
     | 
| 
      
 18 
     | 
    
         
            +
                  @context = context
         
     | 
| 
      
 19 
     | 
    
         
            +
                  @params = context.params
         
     | 
| 
      
 20 
     | 
    
         
            +
                end
         
     | 
| 
      
 21 
     | 
    
         
            +
             
     | 
| 
      
 22 
     | 
    
         
            +
                def execute
         
     | 
| 
      
 23 
     | 
    
         
            +
                  raise NotImplementedError
         
     | 
| 
      
 24 
     | 
    
         
            +
                end
         
     | 
| 
      
 25 
     | 
    
         
            +
              end
         
     | 
| 
      
 26 
     | 
    
         
            +
            end
         
     | 
| 
         @@ -0,0 +1,12 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            module CarbonMU
         
     | 
| 
      
 2 
     | 
    
         
            +
              class CommandContext
         
     | 
| 
      
 3 
     | 
    
         
            +
                attr_reader :enacting_connection, :enactor, :raw_command, :params
         
     | 
| 
      
 4 
     | 
    
         
            +
             
     | 
| 
      
 5 
     | 
    
         
            +
                def initialize(opts)
         
     | 
| 
      
 6 
     | 
    
         
            +
                  @enacting_connection = opts[:enacting_connection] || nil
         
     | 
| 
      
 7 
     | 
    
         
            +
                  @enactor = @enacting_connection.player || nil
         
     | 
| 
      
 8 
     | 
    
         
            +
                  @raw_command = opts[:raw_command] || ""
         
     | 
| 
      
 9 
     | 
    
         
            +
                  @params = opts[:params] || {}
         
     | 
| 
      
 10 
     | 
    
         
            +
                end
         
     | 
| 
      
 11 
     | 
    
         
            +
              end
         
     | 
| 
      
 12 
     | 
    
         
            +
            end
         
     | 
| 
         @@ -0,0 +1,22 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            require 'celluloid'
         
     | 
| 
      
 2 
     | 
    
         
            +
            require 'logger'
         
     | 
| 
      
 3 
     | 
    
         
            +
             
     | 
| 
      
 4 
     | 
    
         
            +
            module CarbonMU
         
     | 
| 
      
 5 
     | 
    
         
            +
              class Configuration
         
     | 
| 
      
 6 
     | 
    
         
            +
                attr_accessor :game_name
         
     | 
| 
      
 7 
     | 
    
         
            +
                attr_reader :logger
         
     | 
| 
      
 8 
     | 
    
         
            +
                attr_accessor :log_ipc_traffic
         
     | 
| 
      
 9 
     | 
    
         
            +
             
     | 
| 
      
 10 
     | 
    
         
            +
                def initialize
         
     | 
| 
      
 11 
     | 
    
         
            +
                  @game_name = 'CarbonMU'
         
     | 
| 
      
 12 
     | 
    
         
            +
                  @logger = Celluloid.logger.tap { |i| i.progname = @game_name }
         
     | 
| 
      
 13 
     | 
    
         
            +
                  @log_ipc_traffic = true
         
     | 
| 
      
 14 
     | 
    
         
            +
                end
         
     | 
| 
      
 15 
     | 
    
         
            +
             
     | 
| 
      
 16 
     | 
    
         
            +
                def logger=(logger)
         
     | 
| 
      
 17 
     | 
    
         
            +
                  raise ArgumentError.new("Not a logger: #{logger}") unless logger.is_a?(Logger)
         
     | 
| 
      
 18 
     | 
    
         
            +
                  Celluloid.logger = logger
         
     | 
| 
      
 19 
     | 
    
         
            +
                  @logger = logger
         
     | 
| 
      
 20 
     | 
    
         
            +
                end
         
     | 
| 
      
 21 
     | 
    
         
            +
              end
         
     | 
| 
      
 22 
     | 
    
         
            +
            end
         
     | 
| 
         @@ -0,0 +1,19 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            module CarbonMU
         
     | 
| 
      
 2 
     | 
    
         
            +
              class Connection
         
     | 
| 
      
 3 
     | 
    
         
            +
                attr_reader :id
         
     | 
| 
      
 4 
     | 
    
         
            +
                attr_accessor :locale
         
     | 
| 
      
 5 
     | 
    
         
            +
                attr_accessor :player
         
     | 
| 
      
 6 
     | 
    
         
            +
             
     | 
| 
      
 7 
     | 
    
         
            +
                # TODO probably need edge type (:telnet, :ssl, etc), or at least interactive true/false
         
     | 
| 
      
 8 
     | 
    
         
            +
                def initialize(id)
         
     | 
| 
      
 9 
     | 
    
         
            +
                  @id = id
         
     | 
| 
      
 10 
     | 
    
         
            +
                  @locale = "en" # TODO configurable default locale
         
     | 
| 
      
 11 
     | 
    
         
            +
                  @player = nil
         
     | 
| 
      
 12 
     | 
    
         
            +
                end
         
     | 
| 
      
 13 
     | 
    
         
            +
             
     | 
| 
      
 14 
     | 
    
         
            +
                def write_translated(msg, args = {})
         
     | 
| 
      
 15 
     | 
    
         
            +
                  translation_args = args.merge(locale: @locale)
         
     | 
| 
      
 16 
     | 
    
         
            +
                  CarbonMU.server.write_to_connection(id, I18n.t(msg, translation_args) + "\n")
         
     | 
| 
      
 17 
     | 
    
         
            +
                end
         
     | 
| 
      
 18 
     | 
    
         
            +
              end
         
     | 
| 
      
 19 
     | 
    
         
            +
            end
         
     | 
| 
         @@ -0,0 +1,16 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            require "i18n"
         
     | 
| 
      
 2 
     | 
    
         
            +
            require "i18n/backend/fallbacks"
         
     | 
| 
      
 3 
     | 
    
         
            +
             
     | 
| 
      
 4 
     | 
    
         
            +
            module CarbonMU
         
     | 
| 
      
 5 
     | 
    
         
            +
              module Internationalization
         
     | 
| 
      
 6 
     | 
    
         
            +
             
     | 
| 
      
 7 
     | 
    
         
            +
                def self.setup
         
     | 
| 
      
 8 
     | 
    
         
            +
                  I18n.enforce_available_locales = false
         
     | 
| 
      
 9 
     | 
    
         
            +
                  I18n.load_path = Dir["config/locales/**/*.yml"] # TODO support for plugins too.
         
     | 
| 
      
 10 
     | 
    
         
            +
                end
         
     | 
| 
      
 11 
     | 
    
         
            +
             
     | 
| 
      
 12 
     | 
    
         
            +
                def self.translate(str, *opts)
         
     | 
| 
      
 13 
     | 
    
         
            +
                  I18n.t(str, opts)
         
     | 
| 
      
 14 
     | 
    
         
            +
                end
         
     | 
| 
      
 15 
     | 
    
         
            +
              end
         
     | 
| 
      
 16 
     | 
    
         
            +
            end
         
     | 
    
        data/lib/core/parser.rb
    ADDED
    
    | 
         @@ -0,0 +1,29 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            module CarbonMU
         
     | 
| 
      
 2 
     | 
    
         
            +
              module Parser
         
     | 
| 
      
 3 
     | 
    
         
            +
                def self.parse_and_execute(enacting_connection, input)
         
     | 
| 
      
 4 
     | 
    
         
            +
                  command_class, params = parse(input)
         
     | 
| 
      
 5 
     | 
    
         
            +
             
     | 
| 
      
 6 
     | 
    
         
            +
                  context = CommandContext.new(enacting_connection: enacting_connection, raw_command: input, params: params)
         
     | 
| 
      
 7 
     | 
    
         
            +
                  command_class.new(context).execute
         
     | 
| 
      
 8 
     | 
    
         
            +
                end
         
     | 
| 
      
 9 
     | 
    
         
            +
             
     | 
| 
      
 10 
     | 
    
         
            +
                def self.parse(input)
         
     | 
| 
      
 11 
     | 
    
         
            +
                  syntax_match_data = {}
         
     | 
| 
      
 12 
     | 
    
         
            +
                  syntax_and_class = @@syntaxes.detect { |syntax, klass| syntax_match_data = syntax.match(input) }
         
     | 
| 
      
 13 
     | 
    
         
            +
             
     | 
| 
      
 14 
     | 
    
         
            +
                  command_class = syntax_and_class.nil? ? UnknownCommand : syntax_and_class[1]
         
     | 
| 
      
 15 
     | 
    
         
            +
                  syntax_match_data ||= {} # if no syntaxes matched
         
     | 
| 
      
 16 
     | 
    
         
            +
             
     | 
| 
      
 17 
     | 
    
         
            +
                  [command_class, syntax_match_data.to_hash]
         
     | 
| 
      
 18 
     | 
    
         
            +
                end
         
     | 
| 
      
 19 
     | 
    
         
            +
             
     | 
| 
      
 20 
     | 
    
         
            +
                def self.register_syntax(syntax, klass)
         
     | 
| 
      
 21 
     | 
    
         
            +
                  @@syntaxes ||= {}
         
     | 
| 
      
 22 
     | 
    
         
            +
                  @@syntaxes[syntax] = klass
         
     | 
| 
      
 23 
     | 
    
         
            +
                end
         
     | 
| 
      
 24 
     | 
    
         
            +
             
     | 
| 
      
 25 
     | 
    
         
            +
                def self.syntaxes
         
     | 
| 
      
 26 
     | 
    
         
            +
                  @@syntaxes
         
     | 
| 
      
 27 
     | 
    
         
            +
                end
         
     | 
| 
      
 28 
     | 
    
         
            +
              end
         
     | 
| 
      
 29 
     | 
    
         
            +
            end
         
     | 
    
        data/lib/core/server.rb
    ADDED
    
    | 
         @@ -0,0 +1,118 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            require 'celluloid/io'
         
     | 
| 
      
 2 
     | 
    
         
            +
            require 'celluloid/zmq'
         
     | 
| 
      
 3 
     | 
    
         
            +
            require 'mongoid'
         
     | 
| 
      
 4 
     | 
    
         
            +
             
     | 
| 
      
 5 
     | 
    
         
            +
            module CarbonMU
         
     | 
| 
      
 6 
     | 
    
         
            +
              class Server
         
     | 
| 
      
 7 
     | 
    
         
            +
                include Celluloid::IO
         
     | 
| 
      
 8 
     | 
    
         
            +
                include Celluloid::Logger
         
     | 
| 
      
 9 
     | 
    
         
            +
                include Celluloid::ZMQ
         
     | 
| 
      
 10 
     | 
    
         
            +
             
     | 
| 
      
 11 
     | 
    
         
            +
                finalizer :shutdown
         
     | 
| 
      
 12 
     | 
    
         
            +
             
     | 
| 
      
 13 
     | 
    
         
            +
                attr_reader :connections
         
     | 
| 
      
 14 
     | 
    
         
            +
             
     | 
| 
      
 15 
     | 
    
         
            +
                def initialize(standalone = false)
         
     | 
| 
      
 16 
     | 
    
         
            +
                  Internationalization.setup
         
     | 
| 
      
 17 
     | 
    
         
            +
             
     | 
| 
      
 18 
     | 
    
         
            +
                  info "*** Starting CarbonMU game server to connect to edge router port #{CarbonMU.edge_router_receive_port}."
         
     | 
| 
      
 19 
     | 
    
         
            +
                  CarbonMU.server = Actor.current
         
     | 
| 
      
 20 
     | 
    
         
            +
             
     | 
| 
      
 21 
     | 
    
         
            +
                  Server.initialize_database
         
     | 
| 
      
 22 
     | 
    
         
            +
                  Server.create_starter_objects
         
     | 
| 
      
 23 
     | 
    
         
            +
             
     | 
| 
      
 24 
     | 
    
         
            +
                  unless standalone
         
     | 
| 
      
 25 
     | 
    
         
            +
                    @ipc_reader = ReadSocket.new
         
     | 
| 
      
 26 
     | 
    
         
            +
                    @ipc_writer = WriteSocket.new(CarbonMU.edge_router_receive_port)
         
     | 
| 
      
 27 
     | 
    
         
            +
                    send_server_started_to_edge_router
         
     | 
| 
      
 28 
     | 
    
         
            +
             
     | 
| 
      
 29 
     | 
    
         
            +
                    async.run
         
     | 
| 
      
 30 
     | 
    
         
            +
             
     | 
| 
      
 31 
     | 
    
         
            +
                    retrieve_existing_connections
         
     | 
| 
      
 32 
     | 
    
         
            +
                  end
         
     | 
| 
      
 33 
     | 
    
         
            +
                end
         
     | 
| 
      
 34 
     | 
    
         
            +
             
     | 
| 
      
 35 
     | 
    
         
            +
                def run
         
     | 
| 
      
 36 
     | 
    
         
            +
                  loop do
         
     | 
| 
      
 37 
     | 
    
         
            +
                    async.handle_edge_router_message(@ipc_reader.read)
         
     | 
| 
      
 38 
     | 
    
         
            +
                  end
         
     | 
| 
      
 39 
     | 
    
         
            +
                end
         
     | 
| 
      
 40 
     | 
    
         
            +
             
     | 
| 
      
 41 
     | 
    
         
            +
                def shutdown
         
     | 
| 
      
 42 
     | 
    
         
            +
                  error "Terminating server!"
         
     | 
| 
      
 43 
     | 
    
         
            +
                end
         
     | 
| 
      
 44 
     | 
    
         
            +
             
     | 
| 
      
 45 
     | 
    
         
            +
                def add_connection(connection_id)
         
     | 
| 
      
 46 
     | 
    
         
            +
                  @connections ||= []
         
     | 
| 
      
 47 
     | 
    
         
            +
                  c = Connection.new(connection_id)
         
     | 
| 
      
 48 
     | 
    
         
            +
                  c.player = Player.superadmin #TODO real login
         
     | 
| 
      
 49 
     | 
    
         
            +
                  @connections << c
         
     | 
| 
      
 50 
     | 
    
         
            +
                end
         
     | 
| 
      
 51 
     | 
    
         
            +
             
     | 
| 
      
 52 
     | 
    
         
            +
                def remove_connection(connection_id)
         
     | 
| 
      
 53 
     | 
    
         
            +
                  @connections.delete_if { |c| c.id == connection_id }
         
     | 
| 
      
 54 
     | 
    
         
            +
                end
         
     | 
| 
      
 55 
     | 
    
         
            +
             
     | 
| 
      
 56 
     | 
    
         
            +
                def handle_command(input, connection_id)
         
     | 
| 
      
 57 
     | 
    
         
            +
                  connection = @connections.find { |c| c.id == connection_id }
         
     | 
| 
      
 58 
     | 
    
         
            +
                  Parser.parse_and_execute(connection, input)
         
     | 
| 
      
 59 
     | 
    
         
            +
                end
         
     | 
| 
      
 60 
     | 
    
         
            +
             
     | 
| 
      
 61 
     | 
    
         
            +
                def write_to_connection(connection_id, str)
         
     | 
| 
      
 62 
     | 
    
         
            +
                  send_message_to_edge_router(:write, connection_id: connection_id, output: str)
         
     | 
| 
      
 63 
     | 
    
         
            +
                end
         
     | 
| 
      
 64 
     | 
    
         
            +
             
     | 
| 
      
 65 
     | 
    
         
            +
                def send_server_started_to_edge_router
         
     | 
| 
      
 66 
     | 
    
         
            +
                  send_message_to_edge_router(:started, port: @ipc_reader.port_number, pid: Process.pid)
         
     | 
| 
      
 67 
     | 
    
         
            +
                end
         
     | 
| 
      
 68 
     | 
    
         
            +
             
     | 
| 
      
 69 
     | 
    
         
            +
                def handle_edge_router_message(input)
         
     | 
| 
      
 70 
     | 
    
         
            +
                  message = IPCMessage.unserialize(input)
         
     | 
| 
      
 71 
     | 
    
         
            +
                  debug "SERVER RECEIVE: #{message}" if CarbonMU.configuration.log_ipc_traffic
         
     | 
| 
      
 72 
     | 
    
         
            +
                  case message.op
         
     | 
| 
      
 73 
     | 
    
         
            +
                  when :command
         
     | 
| 
      
 74 
     | 
    
         
            +
                    handle_command(message.command, message.connection_id)
         
     | 
| 
      
 75 
     | 
    
         
            +
                  when :connect
         
     | 
| 
      
 76 
     | 
    
         
            +
                    add_connection(message.connection_id)
         
     | 
| 
      
 77 
     | 
    
         
            +
                  when :disconnect
         
     | 
| 
      
 78 
     | 
    
         
            +
                    remove_connection(message.connection_id)
         
     | 
| 
      
 79 
     | 
    
         
            +
                  else
         
     | 
| 
      
 80 
     | 
    
         
            +
                    raise ArgumentError, "Unsupported operation '#{message.op}' received from edge router."
         
     | 
| 
      
 81 
     | 
    
         
            +
                  end
         
     | 
| 
      
 82 
     | 
    
         
            +
                end
         
     | 
| 
      
 83 
     | 
    
         
            +
             
     | 
| 
      
 84 
     | 
    
         
            +
                def retrieve_existing_connections
         
     | 
| 
      
 85 
     | 
    
         
            +
                  send_message_to_edge_router(:retrieve_existing_connections)
         
     | 
| 
      
 86 
     | 
    
         
            +
                end
         
     | 
| 
      
 87 
     | 
    
         
            +
             
     | 
| 
      
 88 
     | 
    
         
            +
                def self.trigger_reboot
         
     | 
| 
      
 89 
     | 
    
         
            +
                  Actor[:server].send_reboot_message_to_edge_router
         
     | 
| 
      
 90 
     | 
    
         
            +
                end
         
     | 
| 
      
 91 
     | 
    
         
            +
             
     | 
| 
      
 92 
     | 
    
         
            +
                def send_reboot_message_to_edge_router
         
     | 
| 
      
 93 
     | 
    
         
            +
                  send_message_to_edge_router(:reboot)
         
     | 
| 
      
 94 
     | 
    
         
            +
                end
         
     | 
| 
      
 95 
     | 
    
         
            +
             
     | 
| 
      
 96 
     | 
    
         
            +
                def send_message_to_edge_router(op, params={})
         
     | 
| 
      
 97 
     | 
    
         
            +
                  message = IPCMessage.new(op, params)
         
     | 
| 
      
 98 
     | 
    
         
            +
                  debug "SERVER SEND: #{message}" if CarbonMU.configuration.log_ipc_traffic
         
     | 
| 
      
 99 
     | 
    
         
            +
                  @ipc_writer.send message.serialize
         
     | 
| 
      
 100 
     | 
    
         
            +
                end
         
     | 
| 
      
 101 
     | 
    
         
            +
             
     | 
| 
      
 102 
     | 
    
         
            +
                def self.initialize_database
         
     | 
| 
      
 103 
     | 
    
         
            +
                  Mongoid.logger.level = ::Logger::DEBUG
         
     | 
| 
      
 104 
     | 
    
         
            +
                  Mongoid.load!("mongoid.yml", ENV["MONGOID_ENV"] || :production)
         
     | 
| 
      
 105 
     | 
    
         
            +
                  ::Mongoid::Tasks::Database.create_indexes
         
     | 
| 
      
 106 
     | 
    
         
            +
                end
         
     | 
| 
      
 107 
     | 
    
         
            +
             
     | 
| 
      
 108 
     | 
    
         
            +
                def self.create_starter_objects
         
     | 
| 
      
 109 
     | 
    
         
            +
                  ensure_special_exists(:starting_room, Room, {name: "Starting Room", description: "This is the starting room for newly-created players. Feel free to rename and re-describe it."})
         
     | 
| 
      
 110 
     | 
    
         
            +
                  ensure_special_exists(:lostandfound_room, Room, {name: "Lost & Found Room", description: "This is the room where objects and players go if the thing that was holding them gets destroyed."})
         
     | 
| 
      
 111 
     | 
    
         
            +
                  ensure_special_exists(:superadmin_player, Player, {name: "Superadmin", description: "Obviously the most powerful of his race, it could kill us all."})
         
     | 
| 
      
 112 
     | 
    
         
            +
                end
         
     | 
| 
      
 113 
     | 
    
         
            +
             
     | 
| 
      
 114 
     | 
    
         
            +
                def self.ensure_special_exists(special, klass, attributes)
         
     | 
| 
      
 115 
     | 
    
         
            +
                  klass.create!(attributes.merge(_special: special)) if klass.where(_special: special).count == 0
         
     | 
| 
      
 116 
     | 
    
         
            +
                end
         
     | 
| 
      
 117 
     | 
    
         
            +
              end
         
     | 
| 
      
 118 
     | 
    
         
            +
            end
         
     | 
| 
         @@ -0,0 +1,39 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            module CarbonMU
         
     | 
| 
      
 2 
     | 
    
         
            +
              class EdgeConnection
         
     | 
| 
      
 3 
     | 
    
         
            +
                include Celluloid::IO
         
     | 
| 
      
 4 
     | 
    
         
            +
                include Celluloid::Logger
         
     | 
| 
      
 5 
     | 
    
         
            +
             
     | 
| 
      
 6 
     | 
    
         
            +
                attr_accessor :name
         
     | 
| 
      
 7 
     | 
    
         
            +
                attr_reader :id
         
     | 
| 
      
 8 
     | 
    
         
            +
             
     | 
| 
      
 9 
     | 
    
         
            +
                finalizer :shutdown
         
     | 
| 
      
 10 
     | 
    
         
            +
             
     | 
| 
      
 11 
     | 
    
         
            +
                def initialize(arg = nil)
         
     | 
| 
      
 12 
     | 
    
         
            +
                  @id = SecureRandom.uuid
         
     | 
| 
      
 13 
     | 
    
         
            +
                  after_initialize(arg)
         
     | 
| 
      
 14 
     | 
    
         
            +
                end
         
     | 
| 
      
 15 
     | 
    
         
            +
             
     | 
| 
      
 16 
     | 
    
         
            +
                def after_initialize(arg)
         
     | 
| 
      
 17 
     | 
    
         
            +
                  nil # to be implemented by subclasses, if desired
         
     | 
| 
      
 18 
     | 
    
         
            +
                end
         
     | 
| 
      
 19 
     | 
    
         
            +
             
     | 
| 
      
 20 
     | 
    
         
            +
                def handle_input(input)
         
     | 
| 
      
 21 
     | 
    
         
            +
                  input.chomp!
         
     | 
| 
      
 22 
     | 
    
         
            +
                  Actor[:edge_router].async.send_command_to_server(input, id)
         
     | 
| 
      
 23 
     | 
    
         
            +
                end
         
     | 
| 
      
 24 
     | 
    
         
            +
             
     | 
| 
      
 25 
     | 
    
         
            +
                def run
         
     | 
| 
      
 26 
     | 
    
         
            +
                  raise NotImplementedError
         
     | 
| 
      
 27 
     | 
    
         
            +
                end
         
     | 
| 
      
 28 
     | 
    
         
            +
             
     | 
| 
      
 29 
     | 
    
         
            +
                def shutdown
         
     | 
| 
      
 30 
     | 
    
         
            +
                  before_shutdown
         
     | 
| 
      
 31 
     | 
    
         
            +
                  Actor[:edge_router].async.remove_connection(Actor.current)
         
     | 
| 
      
 32 
     | 
    
         
            +
                end
         
     | 
| 
      
 33 
     | 
    
         
            +
             
     | 
| 
      
 34 
     | 
    
         
            +
                def before_shutdown
         
     | 
| 
      
 35 
     | 
    
         
            +
                  nil # to be implemented by subclasses, if desired
         
     | 
| 
      
 36 
     | 
    
         
            +
                end
         
     | 
| 
      
 37 
     | 
    
         
            +
              end
         
     | 
| 
      
 38 
     | 
    
         
            +
            end
         
     | 
| 
      
 39 
     | 
    
         
            +
             
     | 
| 
         @@ -0,0 +1,104 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            require 'celluloid/autostart'
         
     | 
| 
      
 2 
     | 
    
         
            +
            require 'celluloid/io'
         
     | 
| 
      
 3 
     | 
    
         
            +
            require 'celluloid/zmq'
         
     | 
| 
      
 4 
     | 
    
         
            +
             
     | 
| 
      
 5 
     | 
    
         
            +
            module CarbonMU
         
     | 
| 
      
 6 
     | 
    
         
            +
              class EdgeRouter
         
     | 
| 
      
 7 
     | 
    
         
            +
                include Celluloid::IO
         
     | 
| 
      
 8 
     | 
    
         
            +
                include Celluloid::Logger
         
     | 
| 
      
 9 
     | 
    
         
            +
                include Celluloid::ZMQ
         
     | 
| 
      
 10 
     | 
    
         
            +
             
     | 
| 
      
 11 
     | 
    
         
            +
                finalizer :shutdown
         
     | 
| 
      
 12 
     | 
    
         
            +
             
     | 
| 
      
 13 
     | 
    
         
            +
                attr_reader :receptors, :connections
         
     | 
| 
      
 14 
     | 
    
         
            +
             
     | 
| 
      
 15 
     | 
    
         
            +
                def initialize(host, port)
         
     | 
| 
      
 16 
     | 
    
         
            +
                  info "*** Starting CarbonMU edge router."
         
     | 
| 
      
 17 
     | 
    
         
            +
                  @receptors = TelnetReceptor.new(host,port)
         
     | 
| 
      
 18 
     | 
    
         
            +
                  @connections = []
         
     | 
| 
      
 19 
     | 
    
         
            +
             
     | 
| 
      
 20 
     | 
    
         
            +
                  @ipc_reader = ReadSocket.new
         
     | 
| 
      
 21 
     | 
    
         
            +
                  info "*** Edge router waiting for IPC on port #{@ipc_reader.port_number}"
         
     | 
| 
      
 22 
     | 
    
         
            +
                  async.run
         
     | 
| 
      
 23 
     | 
    
         
            +
             
     | 
| 
      
 24 
     | 
    
         
            +
                  start_server
         
     | 
| 
      
 25 
     | 
    
         
            +
                end
         
     | 
| 
      
 26 
     | 
    
         
            +
             
     | 
| 
      
 27 
     | 
    
         
            +
                def start_server
         
     | 
| 
      
 28 
     | 
    
         
            +
                  spawn("/usr/bin/env ruby start-server-only #{@ipc_reader.port_number}")
         
     | 
| 
      
 29 
     | 
    
         
            +
                end
         
     | 
| 
      
 30 
     | 
    
         
            +
             
     | 
| 
      
 31 
     | 
    
         
            +
                def handle_server_started(pid, port)
         
     | 
| 
      
 32 
     | 
    
         
            +
                  debug "*** Edge router received server IPC start. Pid #{pid}, port #{port}." if CarbonMU.configuration.log_ipc_traffic
         
     | 
| 
      
 33 
     | 
    
         
            +
                  @current_server_pid = pid
         
     | 
| 
      
 34 
     | 
    
         
            +
                  Process.detach(pid)
         
     | 
| 
      
 35 
     | 
    
         
            +
                  @ipc_writer = WriteSocket.new(port)
         
     | 
| 
      
 36 
     | 
    
         
            +
                end
         
     | 
| 
      
 37 
     | 
    
         
            +
             
     | 
| 
      
 38 
     | 
    
         
            +
                def add_connection(connection)
         
     | 
| 
      
 39 
     | 
    
         
            +
                  @connections << connection
         
     | 
| 
      
 40 
     | 
    
         
            +
                  send_connect_to_server(connection)
         
     | 
| 
      
 41 
     | 
    
         
            +
                end
         
     | 
| 
      
 42 
     | 
    
         
            +
             
     | 
| 
      
 43 
     | 
    
         
            +
                def remove_connection(connection)
         
     | 
| 
      
 44 
     | 
    
         
            +
                  @connections.delete(connection)
         
     | 
| 
      
 45 
     | 
    
         
            +
                  send_disconnect_to_server(connection)
         
     | 
| 
      
 46 
     | 
    
         
            +
                end
         
     | 
| 
      
 47 
     | 
    
         
            +
             
     | 
| 
      
 48 
     | 
    
         
            +
                def shutdown
         
     | 
| 
      
 49 
     | 
    
         
            +
                  # TODO Tell all receptors and connections to quit.
         
     | 
| 
      
 50 
     | 
    
         
            +
                  Process.kill("TERM", @current_server_pid)
         
     | 
| 
      
 51 
     | 
    
         
            +
                end
         
     | 
| 
      
 52 
     | 
    
         
            +
             
     | 
| 
      
 53 
     | 
    
         
            +
                def run
         
     | 
| 
      
 54 
     | 
    
         
            +
                  loop do
         
     | 
| 
      
 55 
     | 
    
         
            +
                    async.handle_server_message(@ipc_reader.read)
         
     | 
| 
      
 56 
     | 
    
         
            +
                  end
         
     | 
| 
      
 57 
     | 
    
         
            +
                end
         
     | 
| 
      
 58 
     | 
    
         
            +
             
     | 
| 
      
 59 
     | 
    
         
            +
                def send_connect_to_server(connection)
         
     | 
| 
      
 60 
     | 
    
         
            +
                  send_message_to_server(:connect, connection_id: connection.id)
         
     | 
| 
      
 61 
     | 
    
         
            +
                end
         
     | 
| 
      
 62 
     | 
    
         
            +
             
     | 
| 
      
 63 
     | 
    
         
            +
                def send_disconnect_to_server(connection)
         
     | 
| 
      
 64 
     | 
    
         
            +
                  send_message_to_server(:disconnect, connection_id: connection.id)
         
     | 
| 
      
 65 
     | 
    
         
            +
                end
         
     | 
| 
      
 66 
     | 
    
         
            +
             
     | 
| 
      
 67 
     | 
    
         
            +
                def send_command_to_server(input, connection_id)
         
     | 
| 
      
 68 
     | 
    
         
            +
                  send_message_to_server(:command, command: input, connection_id: connection_id)
         
     | 
| 
      
 69 
     | 
    
         
            +
                end
         
     | 
| 
      
 70 
     | 
    
         
            +
             
     | 
| 
      
 71 
     | 
    
         
            +
                def send_message_to_server(op, params={})
         
     | 
| 
      
 72 
     | 
    
         
            +
                  message = IPCMessage.new(op, params)
         
     | 
| 
      
 73 
     | 
    
         
            +
                  debug "EDGE ROUTER SEND: #{message}" if CarbonMU.configuration.log_ipc_traffic
         
     | 
| 
      
 74 
     | 
    
         
            +
                  @ipc_writer.send message.serialize
         
     | 
| 
      
 75 
     | 
    
         
            +
                end
         
     | 
| 
      
 76 
     | 
    
         
            +
             
     | 
| 
      
 77 
     | 
    
         
            +
                def reboot_server
         
     | 
| 
      
 78 
     | 
    
         
            +
                  warn "Reboot triggered!"
         
     | 
| 
      
 79 
     | 
    
         
            +
                  Process.kill("TERM", @current_server_pid)
         
     | 
| 
      
 80 
     | 
    
         
            +
                  start_server
         
     | 
| 
      
 81 
     | 
    
         
            +
                end
         
     | 
| 
      
 82 
     | 
    
         
            +
             
     | 
| 
      
 83 
     | 
    
         
            +
                def handle_server_message(input)
         
     | 
| 
      
 84 
     | 
    
         
            +
                  message = IPCMessage.unserialize(input)
         
     | 
| 
      
 85 
     | 
    
         
            +
                  debug "EDGE ROUTER RECEIVE: #{message}" if CarbonMU.configuration.log_ipc_traffic
         
     | 
| 
      
 86 
     | 
    
         
            +
                  case message.op
         
     | 
| 
      
 87 
     | 
    
         
            +
                  when :started
         
     | 
| 
      
 88 
     | 
    
         
            +
                    handle_server_started(message.pid, message.port)
         
     | 
| 
      
 89 
     | 
    
         
            +
                  when :write
         
     | 
| 
      
 90 
     | 
    
         
            +
                    conn = @connections.select {|x| x.id == message.connection_id}.first # TODO look for efficiency here
         
     | 
| 
      
 91 
     | 
    
         
            +
                    conn.write(message.output)
         
     | 
| 
      
 92 
     | 
    
         
            +
                  when :reboot
         
     | 
| 
      
 93 
     | 
    
         
            +
                    reboot_server
         
     | 
| 
      
 94 
     | 
    
         
            +
                  when :retrieve_existing_connections
         
     | 
| 
      
 95 
     | 
    
         
            +
                    info 'Sending connections to server...'
         
     | 
| 
      
 96 
     | 
    
         
            +
                    @connections.each do |conn|
         
     | 
| 
      
 97 
     | 
    
         
            +
                      send_connect_to_server(conn)
         
     | 
| 
      
 98 
     | 
    
         
            +
                    end
         
     | 
| 
      
 99 
     | 
    
         
            +
                  else
         
     | 
| 
      
 100 
     | 
    
         
            +
                    raise ArgumentError, "Unsupported operation '#{message.op}' received from Server."
         
     | 
| 
      
 101 
     | 
    
         
            +
                  end
         
     | 
| 
      
 102 
     | 
    
         
            +
                end
         
     | 
| 
      
 103 
     | 
    
         
            +
              end
         
     | 
| 
      
 104 
     | 
    
         
            +
            end
         
     |