acpc_table_manager 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 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