mooncell 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,33 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'singleton'
4
+ require 'forwardable'
5
+
6
+ module Mooncell
7
+ module Protocol
8
+ # @since 0.1.0
9
+ # @api private
10
+ class Registry
11
+ class << self
12
+ extend Forwardable
13
+
14
+ delegate %w[register lookup] => 'instance'
15
+ end
16
+
17
+ include Singleton
18
+
19
+ def initialize
20
+ @protocols = Concurrent::Map.new
21
+ end
22
+
23
+ def register(klass)
24
+ name = klass.name.split('::').last.downcase
25
+ @protocols[name] = klass
26
+ end
27
+
28
+ def lookup(name)
29
+ @protocols[name]
30
+ end
31
+ end
32
+ end
33
+ end
@@ -0,0 +1,70 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'rack'
4
+
5
+ module Mooncell
6
+ module Protocol
7
+ # WebSocket Protocol
8
+ class WebSocket
9
+ require 'mooncell/protocol/websocket/server'
10
+
11
+ include Mooncell::Protocol
12
+
13
+ # @since 0.1.0
14
+ # @api private
15
+ BAD_RESPONSE = [
16
+ 400,
17
+ {},
18
+ []
19
+ ].freeze
20
+
21
+ # Create protocol instance
22
+ #
23
+ # TODO: Generalize protocol behaviors
24
+ #
25
+ # @since 0.1.0
26
+ # @api private
27
+ def initialize(app)
28
+ @app = app
29
+ end
30
+
31
+ # Start Server
32
+ #
33
+ # @since 0.1.0
34
+ # @api private
35
+ def start
36
+ Rack::Handler.default.run(self, options)
37
+ end
38
+
39
+ # Implement Rack interface
40
+ #
41
+ # @param env [Hash] the rack environment
42
+ #
43
+ # @since 0.1.0
44
+ # @api private
45
+ def call(env)
46
+ return BAD_RESPONSE unless Faye::WebSocket.websocket?(env)
47
+
48
+ WebSocket::Server.new(app, env).rack_response
49
+ end
50
+
51
+ # Return options
52
+ #
53
+ # @return [Hash] the server options
54
+ #
55
+ # @since 0.1.0
56
+ # @api private
57
+ def options
58
+ {
59
+ Port: app.configuration.port
60
+ }
61
+ end
62
+
63
+ private
64
+
65
+ # @since 0.1.0
66
+ # @api private
67
+ attr_reader :app
68
+ end
69
+ end
70
+ end
@@ -0,0 +1,78 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'faye/websocket'
4
+ require 'json'
5
+
6
+ module Mooncell
7
+ module Protocol
8
+ class WebSocket
9
+ # WebSocket Server implement
10
+ #
11
+ # @since 0.1.0
12
+ # @api private
13
+ class Server
14
+ # @since 0.1.0
15
+ # @api private
16
+ attr_reader :app
17
+
18
+ # Create WebSocket Server
19
+ #
20
+ # @since 0.1.0
21
+ # @api private
22
+ def initialize(app, env)
23
+ @ws = Faye::WebSocket.new(env)
24
+ @app = app
25
+
26
+ @ws.on :open, method(:open)
27
+ @ws.on :message, method(:message)
28
+ @ws.on :close, method(:close)
29
+ end
30
+
31
+ # Rack Response
32
+ #
33
+ # @since 0.1.0
34
+ # @api private
35
+ def rack_response
36
+ @ws.rack_response
37
+ end
38
+
39
+ # On WebSocket open
40
+ #
41
+ # @since 0.1.0
42
+ # @api private
43
+ def open(_event)
44
+ @conn = Mooncell::Connection.new(self, app)
45
+ end
46
+
47
+ # On WebSocket receive data
48
+ #
49
+ # @since 0.1.0
50
+ # @api private
51
+ def message(event)
52
+ # TODO: Support customize serializer
53
+ params = JSON.parse(event.data)
54
+ app.router.call(@conn, params)
55
+ rescue JSON::ParserError
56
+ # TODO: Handling error
57
+ write(error: -1)
58
+ end
59
+
60
+ # On WebSocket close
61
+ #
62
+ # @since 0.1.0
63
+ # @api private
64
+ def close(_event)
65
+ app.pool.delete(@conn)
66
+ end
67
+
68
+ # Writable API
69
+ #
70
+ # @since 0.1.0
71
+ # @api private
72
+ def write(data)
73
+ @ws.send(data.to_json)
74
+ end
75
+ end
76
+ end
77
+ end
78
+ end
@@ -0,0 +1,87 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'forwardable'
4
+
5
+ module Mooncell
6
+ # Respond Generator
7
+ #
8
+ # @since 0.1.0
9
+ #
10
+ # @example
11
+ #
12
+ # class Move
13
+ # include Mooncell::Respond
14
+ # end
15
+ module Respond
16
+ # @since 0.1.0
17
+ # @api private
18
+ def self.included(base)
19
+ command = Kernel.const_get(base.name.sub(/Responds/, 'Commands'))
20
+
21
+ base.class_eval do
22
+ extend Forwardable
23
+ extend ClassMethods
24
+ include InstanceMethods
25
+
26
+ delegate command.exposures => 'command'
27
+ end
28
+ end
29
+
30
+ # @since 0.1.0
31
+ # @api private
32
+ module ClassMethods
33
+ # @since 0.1.0
34
+ # @api private
35
+ @broadcast = false
36
+
37
+ # Set broadcast
38
+ #
39
+ # @param value [TureClass,FalseClass] should broadcast to all players
40
+ #
41
+ # @since 0.1.0
42
+ # @api private
43
+ def broadcast(value = true)
44
+ @broadcast = value == true
45
+ end
46
+
47
+ # Get broadcast
48
+ #
49
+ # @return [TureClass,FalseClass] is a broadcast respond
50
+ #
51
+ # @since 0.1.0
52
+ # @api private
53
+ def broadcast?
54
+ @broadcast == true
55
+ end
56
+ end
57
+
58
+ # @since 0.1.0
59
+ # @api private
60
+ module InstanceMethods
61
+ # @since 0.1.0
62
+ # @api private
63
+ def initialize(command)
64
+ @command = command
65
+ end
66
+
67
+ # @since 0.1.0
68
+ # @api private
69
+ def send
70
+ response = call
71
+ if self.class.broadcast?
72
+ command.conn.app.pool.each do |conn|
73
+ conn.write(response)
74
+ end
75
+ else
76
+ command.conn.write(response)
77
+ end
78
+ end
79
+
80
+ private
81
+
82
+ # @since 0.1.0
83
+ # @api private
84
+ attr_reader :command
85
+ end
86
+ end
87
+ end
@@ -0,0 +1,56 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'concurrent'
4
+
5
+ module Mooncell
6
+ # Command Dispatcher
7
+ #
8
+ # @since 0.1.0
9
+ # @api private
10
+ class Router
11
+ # Create rotuer instance
12
+ #
13
+ # @since 0.1.0
14
+ # @api private
15
+ def initialize(app)
16
+ @app = app
17
+ @routes = Concurrent::Hash.new
18
+ end
19
+
20
+ # Load routes
21
+ #
22
+ # @since 0.1.0
23
+ # @api private
24
+ def load(code)
25
+ instance_eval(code)
26
+ end
27
+
28
+ # Add command
29
+ #
30
+ # @param name [String] the command name
31
+ # @param command [Mooncell::Command] the command
32
+ #
33
+ # @since 0.1.0
34
+ # @api private
35
+ def command(name, command)
36
+ @routes[name] = command
37
+ end
38
+
39
+ # Execute to command
40
+ #
41
+ # @param params [Hash] the request parameters
42
+ #
43
+ # @since 0.1.0
44
+ # @api private
45
+ def call(connection, params)
46
+ command_name = params.delete('command')
47
+ command_class = @routes[command_name]
48
+ return if command_class.nil?
49
+
50
+ # TODO: Need refactor
51
+ command = Kernel.const_get(command_class).new(connection)
52
+ command.call(params)
53
+ command.respond.send
54
+ end
55
+ end
56
+ end
@@ -0,0 +1,5 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Mooncell
4
+ VERSION = '0.1.0'
5
+ end
@@ -0,0 +1,40 @@
1
+ # frozen_string_literal: true
2
+
3
+ lib = File.expand_path('lib', __dir__)
4
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
5
+ require 'mooncell/version'
6
+
7
+ Gem::Specification.new do |spec|
8
+ spec.name = 'mooncell'
9
+ spec.version = Mooncell::VERSION
10
+ spec.authors = ['蒼時弦也']
11
+ spec.email = ['contact@frost.tw']
12
+
13
+ spec.summary = 'The Domain Driven Design Online Game Server'
14
+ spec.description = 'The Domain Driven Design Online Game Server'
15
+ spec.homepage = 'https://github.com/elct9620/mooncell'
16
+
17
+ spec.files = Dir.chdir(File.expand_path(__dir__)) do
18
+ `git ls-files -z`
19
+ .split("\x0")
20
+ .reject { |f| f.match(%r{^(test|spec|features)/}) }
21
+ end
22
+ spec.bindir = 'bin'
23
+ spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
24
+ spec.require_paths = ['lib']
25
+
26
+ spec.add_development_dependency 'bundler', '~> 1.17'
27
+ spec.add_development_dependency 'bundler-audit', '~> 0.6.1'
28
+ spec.add_development_dependency 'overcommit', '~> 0.51.0'
29
+ spec.add_development_dependency 'rake', '~> 10.0'
30
+ spec.add_development_dependency 'rspec', '~> 3.0'
31
+ spec.add_development_dependency 'rubocop', '~> 0.76.0'
32
+
33
+ spec.add_dependency 'concurrent-ruby', '~> 1.1.0'
34
+ spec.add_dependency 'dotenv', '~> 2.7.5'
35
+ spec.add_dependency 'faye-websocket', '~> 0.10.9'
36
+ spec.add_dependency 'puma', '~> 4.2.1'
37
+ spec.add_dependency 'rack', '~> 2.0'
38
+ spec.add_dependency 'sequel', '~> 5.25.0'
39
+ spec.add_dependency 'zeitwerk', '~> 2.2.0'
40
+ end
metadata ADDED
@@ -0,0 +1,260 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: mooncell
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.0
5
+ platform: ruby
6
+ authors:
7
+ - 蒼時弦也
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2019-10-31 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: bundler
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - "~>"
18
+ - !ruby/object:Gem::Version
19
+ version: '1.17'
20
+ type: :development
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - "~>"
25
+ - !ruby/object:Gem::Version
26
+ version: '1.17'
27
+ - !ruby/object:Gem::Dependency
28
+ name: bundler-audit
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - "~>"
32
+ - !ruby/object:Gem::Version
33
+ version: 0.6.1
34
+ type: :development
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - "~>"
39
+ - !ruby/object:Gem::Version
40
+ version: 0.6.1
41
+ - !ruby/object:Gem::Dependency
42
+ name: overcommit
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - "~>"
46
+ - !ruby/object:Gem::Version
47
+ version: 0.51.0
48
+ type: :development
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - "~>"
53
+ - !ruby/object:Gem::Version
54
+ version: 0.51.0
55
+ - !ruby/object:Gem::Dependency
56
+ name: rake
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - "~>"
60
+ - !ruby/object:Gem::Version
61
+ version: '10.0'
62
+ type: :development
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - "~>"
67
+ - !ruby/object:Gem::Version
68
+ version: '10.0'
69
+ - !ruby/object:Gem::Dependency
70
+ name: rspec
71
+ requirement: !ruby/object:Gem::Requirement
72
+ requirements:
73
+ - - "~>"
74
+ - !ruby/object:Gem::Version
75
+ version: '3.0'
76
+ type: :development
77
+ prerelease: false
78
+ version_requirements: !ruby/object:Gem::Requirement
79
+ requirements:
80
+ - - "~>"
81
+ - !ruby/object:Gem::Version
82
+ version: '3.0'
83
+ - !ruby/object:Gem::Dependency
84
+ name: rubocop
85
+ requirement: !ruby/object:Gem::Requirement
86
+ requirements:
87
+ - - "~>"
88
+ - !ruby/object:Gem::Version
89
+ version: 0.76.0
90
+ type: :development
91
+ prerelease: false
92
+ version_requirements: !ruby/object:Gem::Requirement
93
+ requirements:
94
+ - - "~>"
95
+ - !ruby/object:Gem::Version
96
+ version: 0.76.0
97
+ - !ruby/object:Gem::Dependency
98
+ name: concurrent-ruby
99
+ requirement: !ruby/object:Gem::Requirement
100
+ requirements:
101
+ - - "~>"
102
+ - !ruby/object:Gem::Version
103
+ version: 1.1.0
104
+ type: :runtime
105
+ prerelease: false
106
+ version_requirements: !ruby/object:Gem::Requirement
107
+ requirements:
108
+ - - "~>"
109
+ - !ruby/object:Gem::Version
110
+ version: 1.1.0
111
+ - !ruby/object:Gem::Dependency
112
+ name: dotenv
113
+ requirement: !ruby/object:Gem::Requirement
114
+ requirements:
115
+ - - "~>"
116
+ - !ruby/object:Gem::Version
117
+ version: 2.7.5
118
+ type: :runtime
119
+ prerelease: false
120
+ version_requirements: !ruby/object:Gem::Requirement
121
+ requirements:
122
+ - - "~>"
123
+ - !ruby/object:Gem::Version
124
+ version: 2.7.5
125
+ - !ruby/object:Gem::Dependency
126
+ name: faye-websocket
127
+ requirement: !ruby/object:Gem::Requirement
128
+ requirements:
129
+ - - "~>"
130
+ - !ruby/object:Gem::Version
131
+ version: 0.10.9
132
+ type: :runtime
133
+ prerelease: false
134
+ version_requirements: !ruby/object:Gem::Requirement
135
+ requirements:
136
+ - - "~>"
137
+ - !ruby/object:Gem::Version
138
+ version: 0.10.9
139
+ - !ruby/object:Gem::Dependency
140
+ name: puma
141
+ requirement: !ruby/object:Gem::Requirement
142
+ requirements:
143
+ - - "~>"
144
+ - !ruby/object:Gem::Version
145
+ version: 4.2.1
146
+ type: :runtime
147
+ prerelease: false
148
+ version_requirements: !ruby/object:Gem::Requirement
149
+ requirements:
150
+ - - "~>"
151
+ - !ruby/object:Gem::Version
152
+ version: 4.2.1
153
+ - !ruby/object:Gem::Dependency
154
+ name: rack
155
+ requirement: !ruby/object:Gem::Requirement
156
+ requirements:
157
+ - - "~>"
158
+ - !ruby/object:Gem::Version
159
+ version: '2.0'
160
+ type: :runtime
161
+ prerelease: false
162
+ version_requirements: !ruby/object:Gem::Requirement
163
+ requirements:
164
+ - - "~>"
165
+ - !ruby/object:Gem::Version
166
+ version: '2.0'
167
+ - !ruby/object:Gem::Dependency
168
+ name: sequel
169
+ requirement: !ruby/object:Gem::Requirement
170
+ requirements:
171
+ - - "~>"
172
+ - !ruby/object:Gem::Version
173
+ version: 5.25.0
174
+ type: :runtime
175
+ prerelease: false
176
+ version_requirements: !ruby/object:Gem::Requirement
177
+ requirements:
178
+ - - "~>"
179
+ - !ruby/object:Gem::Version
180
+ version: 5.25.0
181
+ - !ruby/object:Gem::Dependency
182
+ name: zeitwerk
183
+ requirement: !ruby/object:Gem::Requirement
184
+ requirements:
185
+ - - "~>"
186
+ - !ruby/object:Gem::Version
187
+ version: 2.2.0
188
+ type: :runtime
189
+ prerelease: false
190
+ version_requirements: !ruby/object:Gem::Requirement
191
+ requirements:
192
+ - - "~>"
193
+ - !ruby/object:Gem::Version
194
+ version: 2.2.0
195
+ description: The Domain Driven Design Online Game Server
196
+ email:
197
+ - contact@frost.tw
198
+ executables:
199
+ - mooncell
200
+ extensions: []
201
+ extra_rdoc_files: []
202
+ files:
203
+ - ".gitignore"
204
+ - ".overcommit.yml"
205
+ - ".rspec"
206
+ - ".travis.yml"
207
+ - CODE_OF_CONDUCT.md
208
+ - Gemfile
209
+ - README.md
210
+ - Rakefile
211
+ - bin/mooncell
212
+ - lib/mooncell.rb
213
+ - lib/mooncell/application.rb
214
+ - lib/mooncell/application_configuration.rb
215
+ - lib/mooncell/cli.rb
216
+ - lib/mooncell/cli/commands.rb
217
+ - lib/mooncell/cli/commands/base.rb
218
+ - lib/mooncell/cli/commands/console.rb
219
+ - lib/mooncell/cli/commands/registry.rb
220
+ - lib/mooncell/cli/commands/server.rb
221
+ - lib/mooncell/cli/commands/version.rb
222
+ - lib/mooncell/command.rb
223
+ - lib/mooncell/configuration.rb
224
+ - lib/mooncell/connection.rb
225
+ - lib/mooncell/connection_pool.rb
226
+ - lib/mooncell/entity.rb
227
+ - lib/mooncell/env.rb
228
+ - lib/mooncell/environment.rb
229
+ - lib/mooncell/loader.rb
230
+ - lib/mooncell/protocol.rb
231
+ - lib/mooncell/protocol/registry.rb
232
+ - lib/mooncell/protocol/websocket.rb
233
+ - lib/mooncell/protocol/websocket/server.rb
234
+ - lib/mooncell/respond.rb
235
+ - lib/mooncell/router.rb
236
+ - lib/mooncell/version.rb
237
+ - mooncell.gemspec
238
+ homepage: https://github.com/elct9620/mooncell
239
+ licenses: []
240
+ metadata: {}
241
+ post_install_message:
242
+ rdoc_options: []
243
+ require_paths:
244
+ - lib
245
+ required_ruby_version: !ruby/object:Gem::Requirement
246
+ requirements:
247
+ - - ">="
248
+ - !ruby/object:Gem::Version
249
+ version: '0'
250
+ required_rubygems_version: !ruby/object:Gem::Requirement
251
+ requirements:
252
+ - - ">="
253
+ - !ruby/object:Gem::Version
254
+ version: '0'
255
+ requirements: []
256
+ rubygems_version: 3.0.3
257
+ signing_key:
258
+ specification_version: 4
259
+ summary: The Domain Driven Design Online Game Server
260
+ test_files: []