acpc_table_manager 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: ae4fbf6d36f0f5d968cc7c54909698a162beab9b
4
+ data.tar.gz: ab4447f63da11d537944cc16d0b86c40da872139
5
+ SHA512:
6
+ metadata.gz: 108ec4ded055368856ceb64720d600ba48fd1ad27f4d1ec9f436ea134846120ea6c0944a54475a076756849dabcc79dcc88eec698c38be79afbbc54ab08a5742
7
+ data.tar.gz: 3cf8b04a4187e248b44386f7473c4a49365274e11584fd72f018461788a7407e78c160b42371306fbf780ddc98c5bcbcb373ab8a9999572d4fe4e80cfe8483ca
data/.gitignore ADDED
@@ -0,0 +1,10 @@
1
+ /.bundle/
2
+ /.yardoc
3
+ /Gemfile.lock
4
+ /_yardoc/
5
+ /coverage/
6
+ /doc/
7
+ /pkg/
8
+ /spec/reports/
9
+ /tmp/
10
+ /test/tmp
data/.travis.yml ADDED
@@ -0,0 +1,4 @@
1
+ language: ruby
2
+ rvm:
3
+ - 2.1.2
4
+ before_install: gem install bundler -v 1.10.6
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source 'https://rubygems.org'
2
+
3
+ # Specify your gem's dependencies in acpc_backend.gemspec
4
+ gemspec
data/LICENSE.txt ADDED
@@ -0,0 +1,21 @@
1
+ The MIT License (MIT)
2
+
3
+ Copyright (c) 2015 Dustin Morrill
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in
13
+ all copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
21
+ THE SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,58 @@
1
+ # AcpcTableManager
2
+
3
+ Must be able to accomplish the following tasks:
4
+
5
+ - Start a dealer
6
+ - Start a bot and have it connect to the dealer
7
+ - Start multiple bots and have them connect to the dealer
8
+ - Start a proxy and connect it to the dealer
9
+ - Send actions to the proxy for them to be played
10
+ - Ensure dealer processes are killed when matches are finished
11
+ - Ensure the number of matches being run is less than set maximum
12
+ - Manage a queue of matches
13
+ - Start the next match in the queue when one finishes
14
+ - Manage a pool of port on which remote bots can connect to dealers
15
+
16
+ The following tasks can be done in parallel:
17
+
18
+ - Playing actions
19
+ - Starting proxies
20
+ - Starting bots
21
+
22
+ Everything else must be done sequentially.
23
+
24
+ ## Installation
25
+
26
+ Add this line to your application's Gemfile:
27
+
28
+ ```ruby
29
+ gem 'acpc_table_manager'
30
+ ```
31
+
32
+ And then execute:
33
+
34
+ $ bundle
35
+
36
+ Or install it yourself as:
37
+
38
+ $ gem install acpc_table_manager
39
+
40
+ ## Usage
41
+
42
+ TODO: Write usage instructions here
43
+
44
+ ## Development
45
+
46
+ After checking out the repo, run `bin/setup` to install dependencies. Then, run `rake test` to run the tests. You can also run `bin/console` for an interactive prompt that will allow you to experiment.
47
+
48
+ To install this gem onto your local machine, run `bundle exec rake install`. To release a new version, update the version number in `version.rb`, and then run `bundle exec rake release`, which will create a git tag for the version, push git commits and tags, and push the `.gem` file to [rubygems.org](https://rubygems.org).
49
+
50
+ ## Contributing
51
+
52
+ Bug reports and pull requests are welcome on GitHub at https://github.com/[USERNAME]/acpc_table_manager.
53
+
54
+
55
+ ## License
56
+
57
+ The gem is available as open source under the terms of the [MIT License](http://opensource.org/licenses/MIT).
58
+
data/Rakefile ADDED
@@ -0,0 +1,10 @@
1
+ require "bundler/gem_tasks"
2
+ require "rake/testtask"
3
+
4
+ Rake::TestTask.new(:test) do |t|
5
+ t.libs << "test"
6
+ t.libs << "lib"
7
+ t.test_files = FileList['test/**/*_test.rb']
8
+ end
9
+
10
+ task :default => :test
@@ -0,0 +1,55 @@
1
+ # coding: utf-8
2
+ lib = File.expand_path('../lib', __FILE__)
3
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
+ require 'acpc_table_manager/version'
5
+
6
+ Gem::Specification.new do |spec|
7
+ spec.name = "acpc_table_manager"
8
+ spec.version = AcpcTableManager::VERSION
9
+ spec.authors = ["Dustin Morrill"]
10
+ spec.email = ["dmorrill10@gmail.com"]
11
+
12
+ spec.summary = %q{Backend components to the ACPC Poker GUI Client}
13
+ spec.description = %q{Backend components to the ACPC Poker GUI Client. Includes a player that saves states from the dealer to persistent storage, and components to start, stop, and manage match components.}
14
+ spec.homepage = "https://github.com/dmorrill10/acpc_table_manager"
15
+ spec.license = "MIT"
16
+
17
+ spec.files = `git ls-files -z`.split("\x0").reject { |f| f.match(%r{^(test|spec|features)/}) }
18
+ spec.bindir = "exe"
19
+ spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
20
+ spec.require_paths = ["lib"]
21
+
22
+ # To send emails
23
+ spec.add_dependency "pony"
24
+
25
+ # For persistence
26
+ spec.add_dependency 'origin', '~>1.0'
27
+ spec.add_dependency 'moped', '~>1.4'
28
+ spec.add_dependency "mongoid", '~> 3.1'
29
+
30
+ # For message passing
31
+ spec.add_dependency 'redis', '~> 3.2'
32
+
33
+ # For poker logic
34
+ spec.add_dependency "acpc_poker_types"
35
+ spec.add_dependency 'acpc_dealer', '~> 2.0'
36
+ spec.add_dependency 'acpc_poker_player_proxy', '~> 1.1'
37
+
38
+ # Simple exception email notifications
39
+ spec.add_dependency 'rusen'
40
+
41
+ # To run processes asynchronously
42
+ spec.add_dependency 'process_runner', '~> 0.0'
43
+
44
+ # For better errors
45
+ spec.add_dependency 'contextual_exceptions'
46
+
47
+ # For better logging
48
+ spec.add_dependency 'awesome_print'
49
+
50
+ spec.add_development_dependency "bundler", "~> 1.10"
51
+ spec.add_development_dependency "rake", "~> 10.0"
52
+ spec.add_development_dependency "minitest"
53
+ spec.add_development_dependency "mocha"
54
+ spec.add_development_dependency "pry"
55
+ end
data/bin/console ADDED
@@ -0,0 +1,16 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require "bundler/setup"
4
+ require "acpc_table_manager"
5
+
6
+ # You can add fixtures and/or initialization code here to make experimenting
7
+ # with your gem easier. You can also use a different console, if you like.
8
+
9
+ begin
10
+ require 'pry'
11
+ Pry.start
12
+ rescue LoadError
13
+ require "irb"
14
+ IRB.start
15
+ end
16
+
data/bin/setup ADDED
@@ -0,0 +1,7 @@
1
+ #!/bin/bash
2
+ set -euo pipefail
3
+ IFS=$'\n\t'
4
+
5
+ bundle install
6
+
7
+ # Do any other automated setup that you need to do here
@@ -0,0 +1,63 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require 'acpc_table_manager'
4
+ require 'redis'
5
+ require 'json'
6
+ require 'optparse'
7
+
8
+
9
+ ARGV << '-h' if ARGV.empty?
10
+
11
+ options = {}
12
+ OptionParser.new do |opts|
13
+ opts.banner = "Usage: #{$0} [options]"
14
+
15
+ opts.on_tail("-h", "--help", "Show this message") do
16
+ puts opts
17
+ exit
18
+ end
19
+
20
+ opts.on("-t", "--table_manager TABLE MANAGER CONFIG", "Table manager configuration file.") do |c|
21
+ options[:table_manager_config] = File.expand_path c, Dir.pwd
22
+ end
23
+ opts.on("-r", "--redis REDIS CONFIG", "Redis configuration file.") do |c|
24
+ options[:redis_config] = File.expand_path c, Dir.pwd
25
+ end
26
+ opts.on("-e", "--env [ENVIRONMENT MODE]", "The environment mode to run in, such as 'development' or 'production'.") do |e|
27
+ options[:environment_mode] = e if e && !e.empty?
28
+ end
29
+ end.parse!
30
+
31
+ raise OptionParser::MissingArgument.new('TABLE MANAGER CONFIG') unless options[:table_manager_config]
32
+ raise OptionParser::MissingArgument.new('REDIS CONFIG') unless options[:redis_config]
33
+
34
+ raise OptionParser::ArgumentError.new("#{options[:table_manager_config]} doesn't exist.") unless File.exist?(options[:table_manager_config])
35
+ raise OptionParser::ArgumentError.new("#{options[:redis_config]} doesn't exist.") unless File.exist?(options[:redis_config])
36
+
37
+ REDIS_CONFIG = YAML.load_file(options[:redis_config]).symbolize_keys
38
+ DFLT = REDIS_CONFIG[:default].symbolize_keys
39
+ redis = Redis.new(
40
+ if options[:environment_mode] && REDIS_CONFIG[options[:environment_mode].to_sym]
41
+ DFLT.merge(REDIS_CONFIG[options[:environment_mode].to_sym].symbolize_keys)
42
+ else
43
+ DFLT
44
+ end
45
+ )
46
+
47
+ CONFIG_FILE = options[:table_manager_config]
48
+
49
+ AcpcTableManager.load! CONFIG_FILE
50
+ table_manager = AcpcTableManager::TableManager.new
51
+ loop do
52
+ message = redis.blpop("backend", :timeout => AcpcTableManager.config.maintenance_interval_s)
53
+ if message
54
+ data = JSON.parse message[1]
55
+ if data['request'] == 'reload'
56
+ AcpcTableManager.load! CONFIG_FILE
57
+ else
58
+ table_manager.perform! data['request'], data['params']
59
+ end
60
+ else
61
+ table_manager.maintain!
62
+ end
63
+ end
@@ -0,0 +1,17 @@
1
+ require_relative "acpc_table_manager/version"
2
+ require_relative "acpc_table_manager/config"
3
+ require_relative "acpc_table_manager/match"
4
+ require_relative "acpc_table_manager/match_slice"
5
+ require_relative "acpc_table_manager/match_view"
6
+ require_relative "acpc_table_manager/monkey_patches"
7
+ require_relative "acpc_table_manager/opponents"
8
+ require_relative "acpc_table_manager/dealer"
9
+ require_relative "acpc_table_manager/param_retrieval"
10
+ require_relative "acpc_table_manager/proxy"
11
+ require_relative "acpc_table_manager/simple_logging"
12
+ require_relative "acpc_table_manager/table_manager"
13
+ require_relative "acpc_table_manager/table_queue"
14
+ require_relative "acpc_table_manager/utils"
15
+
16
+ module AcpcTableManager
17
+ end
@@ -0,0 +1,180 @@
1
+ require 'socket'
2
+ require 'json'
3
+ require 'mongoid'
4
+ require 'rusen'
5
+ require 'contextual_exceptions'
6
+ require 'acpc_dealer'
7
+
8
+ require_relative 'simple_logging'
9
+ using SimpleLogging::MessageFormatting
10
+
11
+ require_relative 'utils'
12
+
13
+ module AcpcTableManager
14
+ class Config
15
+ include SimpleLogging
16
+
17
+ THIS_MACHINE = Socket.gethostname
18
+ DEALER_HOST = THIS_MACHINE
19
+
20
+ attr_reader :file, :log_directory, :my_log_directory, :match_log_directory
21
+
22
+ def initialize(file_path, log_directory_, match_log_directory_, interpolation_hash)
23
+ @file = file_path
24
+ JSON.parse(File.read(file_path)).each do |constant, val|
25
+ define_singleton_method(constant.to_sym) do
26
+ ::AcpcTableManager.interpolate_all_strings(val, interpolation_hash)
27
+ end
28
+ end
29
+ @log_directory = log_directory_
30
+ @match_log_directory = match_log_directory_
31
+ @my_log_directory = File.join(@log_directory, 'acpc_table_manager')
32
+ @logger = Logger.from_file_name(File.join(@my_log_directory, 'config.log'))
33
+ end
34
+
35
+ def this_machine() THIS_MACHINE end
36
+ def dealer_host() DEALER_HOST end
37
+ end
38
+
39
+ class ExhibitionConfig
40
+ include SimpleLogging
41
+
42
+ attr_reader :file
43
+
44
+ def initialize(file_path, interpolation_hash, logger = Logger.new(STDOUT))
45
+ @logger = logger
46
+ @file = file_path
47
+ JSON.parse(File.read(file_path)).each do |constant, val|
48
+ interpolated_val = ::AcpcTableManager.interpolate_all_strings(val, interpolation_hash)
49
+ log(__method__, {adding: {method: constant, value: interpolated_val}})
50
+
51
+ instance_variable_set("@#{constant}".to_sym, interpolated_val)
52
+ define_singleton_method(constant.to_sym) do
53
+ instance_variable_get("@#{constant}".to_sym)
54
+ end
55
+ end
56
+ unless @special_ports_to_dealer
57
+ @special_ports_to_dealer = []
58
+ log(__method__, {adding: {method: 'special_ports_to_dealer', value: @special_ports_to_dealer}})
59
+ define_singleton_method(:special_ports_to_dealer) do
60
+ instance_variable_get(:@special_ports_to_dealer)
61
+ end
62
+ end
63
+ end
64
+
65
+ # @return [Array<Class>] Returns only the names that correspond to bot runner
66
+ # classes as those classes.
67
+ def bots(game_def_key, *player_names)
68
+ game_def_key = game_def_key.to_s
69
+ if @games[game_def_key]
70
+ if @games[game_def_key]['opponents']
71
+ player_names.reduce({}) do |bot_map, name|
72
+ bot_map[name] = @games[game_def_key]['opponents'][name] if @games[game_def_key]['opponents'][name]
73
+ bot_map
74
+ end
75
+ else
76
+ log(__method__, {warning: "Game '#{game_def_key}' has no opponents."}, Logger::Severity::WARN)
77
+ {}
78
+ end
79
+ else
80
+ log(__method__, {warning: "Unrecognized game, '#{game_def_key}'."}, Logger::Severity::WARN)
81
+ {}
82
+ end
83
+ end
84
+ end
85
+
86
+ class UninitializedError < StandardError
87
+ include ContextualExceptions::ContextualError
88
+ end
89
+
90
+ def self.raise_uninitialized
91
+ raise UninitializedError.new(
92
+ "Unable to complete with AcpcTableManager uninitialized. Please initialize AcpcTableManager with configuration settings by calling AcpcTableManager.load! with a (YAML) configuration file name."
93
+ )
94
+ end
95
+
96
+ @@config = nil
97
+
98
+ def self.config
99
+ if @@config
100
+ @@config
101
+ else
102
+ raise_uninitialized
103
+ end
104
+ end
105
+
106
+ @@exhibition_config = nil
107
+ def self.exhibition_config
108
+ if @@exhibition_config
109
+ @@exhibition_config
110
+ else
111
+ raise_uninitialized
112
+ end
113
+ end
114
+
115
+ @@is_initialized = false
116
+
117
+ def self.load_config!(config_data, yaml_directory = File.pwd)
118
+ interpolation_hash = {
119
+ pwd: yaml_directory,
120
+ home: Dir.home,
121
+ :~ => Dir.home,
122
+ dealer_directory: AcpcDealer::DEALER_DIRECTORY
123
+ }
124
+ config = interpolate_all_strings(config_data, interpolation_hash)
125
+
126
+ @@config = Config.new(
127
+ config['table_manager_constants'],
128
+ config['log_directory'],
129
+ config['match_log_directory'],
130
+ interpolation_hash
131
+ )
132
+ @@exhibition_config = ExhibitionConfig.new(
133
+ config['exhibition_constants'],
134
+ interpolation_hash,
135
+ Logger.from_file_name(File.join(@@config.my_log_directory, 'exhibition_config.log'))
136
+ )
137
+
138
+ Mongoid.logger = Logger.from_file_name(File.join(@@config.log_directory, 'mongoid.log'))
139
+ Mongoid.load!(config['mongoid_config'], config['mongoid_env'].to_sym)
140
+
141
+ if config['error_report']
142
+ Rusen.settings.sender_address = config['error_report']['sender']
143
+ Rusen.settings.exception_recipients = config['error_report']['recipients']
144
+
145
+ Rusen.settings.outputs = config['error_report']['outputs'] || [:email]
146
+ Rusen.settings.sections = config['error_report']['sections'] || [:backtrace]
147
+ Rusen.settings.email_prefix = config['error_report']['email_prefix'] || '[ERROR] '
148
+ Rusen.settings.smtp_settings = config['error_report']['smtp']
149
+ else
150
+ @@config.log(__method__, {warning: "Email reporting disabled. Please set email configuration to enable this feature."}, Logger::Severity::WARN)
151
+ end
152
+
153
+ @@is_initialized = true
154
+ end
155
+
156
+ def self.load!(config_file_path)
157
+ load_config! YAML.load_file(config_file_path), File.dirname(config_file_path)
158
+ end
159
+
160
+ def self.notify(exception)
161
+ Rusen.notify exception
162
+ end
163
+
164
+ def self.initialized?
165
+ @@is_initialized
166
+ end
167
+
168
+ def self.raise_if_uninitialized
169
+ raise_uninitialized unless initialized?
170
+ end
171
+
172
+ def self.new_log(log_file_name)
173
+ raise_if_uninitialized
174
+ Logger.from_file_name(File.join(@@config.my_log_directory, log_file_name)).with_metadata!
175
+ end
176
+
177
+ def self.unload!
178
+ @@is_initialized = false
179
+ end
180
+ end