krakenlab 2018.01.07
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/.pronto.yml +11 -0
- data/.rspec +3 -0
- data/.rubocop.yml +51 -0
- data/.travis.yml +19 -0
- data/Dangerfile +57 -0
- data/Gemfile +4 -0
- data/LICENSE +21 -0
- data/README.md +156 -0
- data/Rakefile +18 -0
- data/bin/console +14 -0
- data/bin/kraken +14 -0
- data/bin/setup +8 -0
- data/kraken.gemspec +46 -0
- data/lib/kraken.rb +15 -0
- data/lib/kraken/constants/project.rb +64 -0
- data/lib/kraken/core/app.rb +46 -0
- data/lib/kraken/core/client.rb +108 -0
- data/lib/kraken/core/config.rb +39 -0
- data/lib/kraken/core/connection.rb +21 -0
- data/lib/kraken/core/handlers/factory.rb +14 -0
- data/lib/kraken/core/handlers/godot30_handler.rb +16 -0
- data/lib/kraken/core/handlers/handler.rb +150 -0
- data/lib/kraken/core/listener.rb +28 -0
- data/lib/kraken/core/log.rb +50 -0
- data/lib/kraken/models/db.rb +24 -0
- data/lib/kraken/models/model.rb +25 -0
- data/lib/kraken/triggers/trigger.rb +25 -0
- data/lib/kraken/version.rb +3 -0
- metadata +374 -0
data/lib/kraken.rb
ADDED
@@ -0,0 +1,15 @@
|
|
1
|
+
require 'kraken/version'
|
2
|
+
|
3
|
+
# Main module from Kraken Framework
|
4
|
+
module Kraken
|
5
|
+
end
|
6
|
+
|
7
|
+
require 'kraken/core/client'
|
8
|
+
require 'kraken/core/config'
|
9
|
+
require 'kraken/core/listener'
|
10
|
+
require 'kraken/core/log'
|
11
|
+
require 'kraken/core/app'
|
12
|
+
|
13
|
+
require 'kraken/models/model'
|
14
|
+
|
15
|
+
require 'kraken/triggers/trigger'
|
@@ -0,0 +1,64 @@
|
|
1
|
+
module Kraken
|
2
|
+
APP_FILE = "require 'yaml'\n
|
3
|
+
Kraken::Config.instance.setup do |config|
|
4
|
+
config.server name: 'app name', version: '1.0', handler: :godot_30
|
5
|
+
config.add_trigger klass: Kraken::Trigger
|
6
|
+
end\n
|
7
|
+
Kraken::Migrations.configure do |c|
|
8
|
+
c.schema_format = :ruby
|
9
|
+
c.db_dir = 'db'
|
10
|
+
c.yaml_config = 'config/db.yml'
|
11
|
+
c.migrations_paths = ['db/migrate']
|
12
|
+
end
|
13
|
+
".freeze
|
14
|
+
|
15
|
+
CONNECTION_FILE = "class Kraken::Connection < Kraken::MemoryModel
|
16
|
+
def on_delete; end\n
|
17
|
+
def authenticate
|
18
|
+
true
|
19
|
+
end
|
20
|
+
end".freeze
|
21
|
+
|
22
|
+
DB_FILE = "server:
|
23
|
+
adapter: postgresql
|
24
|
+
database: kraken
|
25
|
+
encoding: utf8
|
26
|
+
host: localhost
|
27
|
+
username: postgres
|
28
|
+
password: postgres".freeze
|
29
|
+
|
30
|
+
RAKEFILE_FILE = "require 'kraken'\n
|
31
|
+
Kraken::App.load_app
|
32
|
+
Kraken::Migrations.load_tasks\n
|
33
|
+
task :default do
|
34
|
+
sh 'bundle exec kraken -s'
|
35
|
+
end\n
|
36
|
+
task :console do
|
37
|
+
sh 'bundle exec kraken -d'
|
38
|
+
end\n
|
39
|
+
task :test do
|
40
|
+
sh 'rubocop'
|
41
|
+
sh 'bundle exec rspec'
|
42
|
+
end\n
|
43
|
+
task :migrate do
|
44
|
+
sh 'bundle exec kraken -m'
|
45
|
+
end".freeze
|
46
|
+
|
47
|
+
GEMFILE_FILE = "source 'https://rubygems.org' do
|
48
|
+
gem 'krakenlab', '#{Kraken::VERSION}'\n
|
49
|
+
gem 'rspec'
|
50
|
+
gem 'rubocop'
|
51
|
+
end
|
52
|
+
".freeze
|
53
|
+
|
54
|
+
GITIGNORE_FILE = '*.lock'.freeze
|
55
|
+
|
56
|
+
PROJECT_TREE = {
|
57
|
+
'app' => { 'triggers' => {}, 'validators' => {}, 'models' => { 'database' => {}, 'memory' => {} } },
|
58
|
+
'config' => { 'app.rb' => APP_FILE, 'connection.rb' => CONNECTION_FILE, 'db.yml' => DB_FILE },
|
59
|
+
'db' => { 'seeds.rb' => '', 'migrate' => {} },
|
60
|
+
'Rakefile' => RAKEFILE_FILE,
|
61
|
+
'Gemfile' => GEMFILE_FILE,
|
62
|
+
'.gitignore' => GITIGNORE_FILE
|
63
|
+
}.freeze
|
64
|
+
end
|
@@ -0,0 +1,46 @@
|
|
1
|
+
require 'irb'
|
2
|
+
require 'require_all'
|
3
|
+
require 'project_creator'
|
4
|
+
require 'kraken/constants/project'
|
5
|
+
|
6
|
+
module Kraken
|
7
|
+
# This class are used for load and create kraken applications!
|
8
|
+
class App
|
9
|
+
def self.load_app
|
10
|
+
require_all 'app/validators' if File.exist? 'app/validators'
|
11
|
+
require_all 'app' if File.exist? 'app'
|
12
|
+
require_all 'config' if File.exist? 'config'
|
13
|
+
end
|
14
|
+
|
15
|
+
def self.create_app(name)
|
16
|
+
{ name.to_s => PROJECT_TREE }.create_project
|
17
|
+
exit 0
|
18
|
+
end
|
19
|
+
|
20
|
+
def self.print_version
|
21
|
+
puts 'KrakenLab'
|
22
|
+
puts "-v #{Kraken::VERSION}"
|
23
|
+
exit 0
|
24
|
+
end
|
25
|
+
|
26
|
+
def self.print_help
|
27
|
+
print_version
|
28
|
+
puts 'kraken -n app_name: Create a new kraken app'
|
29
|
+
puts 'kraken -s: start the created app'
|
30
|
+
puts 'kraken -v: show the version'
|
31
|
+
puts 'kraken -d: start a console'
|
32
|
+
puts ''
|
33
|
+
|
34
|
+
puts 'rake db:* for migrations operations. See more about ActiveRecord'
|
35
|
+
end
|
36
|
+
|
37
|
+
def self.start_console
|
38
|
+
IRB.start(__FILE__)
|
39
|
+
exit 0
|
40
|
+
end
|
41
|
+
|
42
|
+
def self.start_server
|
43
|
+
Kraken::Listener.new.join
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
@@ -0,0 +1,108 @@
|
|
1
|
+
require 'socket'
|
2
|
+
|
3
|
+
module Kraken
|
4
|
+
# A simple client for KrakenLab server.
|
5
|
+
# You can use this class to Debug the server with `kraken -c`
|
6
|
+
# or implements your game using gosu gem!
|
7
|
+
#
|
8
|
+
# a = Kraken::Client.new 'user', 'pass'
|
9
|
+
# a.connect 'localhost'
|
10
|
+
# a.call 'module::krakentrigger', {a: 2, b: [2,3,4], c: 'haha'}
|
11
|
+
# a.call 'module::krakentrigger', 'call only this'
|
12
|
+
# a.call 'module::krakentrigger', ['or this', 3]
|
13
|
+
class Client
|
14
|
+
def initialize(user, pass, version)
|
15
|
+
@user = user
|
16
|
+
@pass = pass
|
17
|
+
@version = version
|
18
|
+
end
|
19
|
+
|
20
|
+
def close
|
21
|
+
@socket.close unless @socket.nil?
|
22
|
+
end
|
23
|
+
|
24
|
+
def connect(host, port = 3030)
|
25
|
+
@socket = TCPSocket.new(host, port)
|
26
|
+
write @version
|
27
|
+
write @user
|
28
|
+
write @pass
|
29
|
+
raise 'connection refused' unless read == 'ok'
|
30
|
+
rescue StandardError
|
31
|
+
raise 'connection refused'
|
32
|
+
end
|
33
|
+
|
34
|
+
def call(method, params)
|
35
|
+
write method
|
36
|
+
write to_args(params)
|
37
|
+
read_args
|
38
|
+
end
|
39
|
+
|
40
|
+
private
|
41
|
+
|
42
|
+
def read
|
43
|
+
r = @socket.gets
|
44
|
+
raise 'connection lost' if r.nil?
|
45
|
+
r.chomp
|
46
|
+
end
|
47
|
+
|
48
|
+
def read_args
|
49
|
+
type = read
|
50
|
+
case type
|
51
|
+
when 'h'
|
52
|
+
return read_hash
|
53
|
+
when 'v'
|
54
|
+
return read_vector
|
55
|
+
when 'n'
|
56
|
+
return nil
|
57
|
+
when 'a'
|
58
|
+
return read
|
59
|
+
end
|
60
|
+
end
|
61
|
+
|
62
|
+
def read_hash
|
63
|
+
n = read.to_i
|
64
|
+
awns = {}
|
65
|
+
n.times { awns[read.to_sym] = read_args }
|
66
|
+
awns
|
67
|
+
end
|
68
|
+
|
69
|
+
def read_vector
|
70
|
+
n = read.to_i
|
71
|
+
awns = []
|
72
|
+
n.times { awns << read_args }
|
73
|
+
awns
|
74
|
+
end
|
75
|
+
|
76
|
+
def write(txt)
|
77
|
+
@socket.puts txt.chomp
|
78
|
+
end
|
79
|
+
|
80
|
+
def to_args(obj)
|
81
|
+
case obj
|
82
|
+
when Hash
|
83
|
+
return "h\n#{obj.size}\n#{hash_protocol obj}"
|
84
|
+
when Array
|
85
|
+
return "v\n#{obj.size}\n#{vector_protocol obj}"
|
86
|
+
when NilClass
|
87
|
+
return 'n'
|
88
|
+
end
|
89
|
+
absolute_value(obj)
|
90
|
+
end
|
91
|
+
|
92
|
+
def hash_protocol(obj)
|
93
|
+
ret = ''
|
94
|
+
obj.each_pair { |key, value| ret += "#{key}\n#{to_args value}\n" }
|
95
|
+
ret.chomp
|
96
|
+
end
|
97
|
+
|
98
|
+
def vector_protocol(obj)
|
99
|
+
ret = ''
|
100
|
+
obj.each { |value| ret += "#{to_args value}\n" }
|
101
|
+
ret.chomp
|
102
|
+
end
|
103
|
+
|
104
|
+
def absolute_value(obj)
|
105
|
+
"a\n#{obj}"
|
106
|
+
end
|
107
|
+
end
|
108
|
+
end
|
@@ -0,0 +1,39 @@
|
|
1
|
+
require 'singleton'
|
2
|
+
|
3
|
+
module Kraken
|
4
|
+
# Configure the kraken framework.
|
5
|
+
# You can configure the server, postgre and redis.
|
6
|
+
# You can configure the events in server.
|
7
|
+
# Yes! You can configure other plugins here!
|
8
|
+
#
|
9
|
+
# Kraken::Config.instance.setup do |config|
|
10
|
+
# config.server name: 'hehe'
|
11
|
+
# end
|
12
|
+
class Config
|
13
|
+
include Singleton
|
14
|
+
|
15
|
+
attr_reader :server_name, :server_version, :server_handler
|
16
|
+
attr_reader :triggers
|
17
|
+
|
18
|
+
def setup
|
19
|
+
yield self
|
20
|
+
end
|
21
|
+
|
22
|
+
def server(name: 'kraken app', version: 'valid version', handler: :default)
|
23
|
+
@server_name = name
|
24
|
+
@server_version = version
|
25
|
+
|
26
|
+
raise 'invalid parser' unless HANDLERS.include? handler
|
27
|
+
|
28
|
+
@server_handler = handler
|
29
|
+
end
|
30
|
+
|
31
|
+
def add_trigger(klass: Kraken::Trigger)
|
32
|
+
raise 'Klass needs to inherit Kraken::Trigger' unless klass <= Kraken::Trigger
|
33
|
+
|
34
|
+
@triggers ||= {}
|
35
|
+
@triggers[klass.to_s.downcase] = klass
|
36
|
+
Kraken::Log.info "trigger [#{klass.to_s.downcase}] loaded"
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
@@ -0,0 +1,21 @@
|
|
1
|
+
require 'kraken/models/model'
|
2
|
+
|
3
|
+
module Kraken
|
4
|
+
# The most trivial node
|
5
|
+
class Connection < MemoryModel
|
6
|
+
attribute :user
|
7
|
+
attribute :pass
|
8
|
+
|
9
|
+
index :user
|
10
|
+
|
11
|
+
# How are defined it is a uniq user authenticated in Kraken Network
|
12
|
+
def single_user?
|
13
|
+
Kraken::Connection.find(user: user).size <= 1
|
14
|
+
end
|
15
|
+
|
16
|
+
# Validate if the credentials are correct
|
17
|
+
def authenticate
|
18
|
+
true
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
@@ -0,0 +1,14 @@
|
|
1
|
+
require 'kraken/core/handlers/handler'
|
2
|
+
require 'kraken/core/handlers/godot30_handler'
|
3
|
+
|
4
|
+
module Kraken
|
5
|
+
# This class create the handler defined at Config
|
6
|
+
class HandlerFactory
|
7
|
+
def self.create(socket)
|
8
|
+
parser = Kraken::Config.instance.server_handler
|
9
|
+
|
10
|
+
return Kraken::Godot30Handler.new(socket) if parser == :godot_30
|
11
|
+
Kraken::Handler.new(socket)
|
12
|
+
end
|
13
|
+
end
|
14
|
+
end
|
@@ -0,0 +1,16 @@
|
|
1
|
+
require 'kraken/core/handlers/handler'
|
2
|
+
|
3
|
+
module Kraken
|
4
|
+
# This class made the handler with godot 3.0
|
5
|
+
# To use this handler, setup this line in config file:
|
6
|
+
# config.server name: 'app name', version: '1.0', handler: :godot_30
|
7
|
+
class Godot30Handler < Kraken::Handler
|
8
|
+
def read
|
9
|
+
string_length = @socket.read(4).unpack('L<').first
|
10
|
+
raise 'connection lost' if string_length.nil?
|
11
|
+
line = @socket.read(string_length)
|
12
|
+
raise 'connection lost' if line.nil?
|
13
|
+
line.chomp
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
@@ -0,0 +1,150 @@
|
|
1
|
+
require 'socket'
|
2
|
+
require 'thread'
|
3
|
+
|
4
|
+
require 'kraken/core/connection'
|
5
|
+
|
6
|
+
module Kraken
|
7
|
+
HANDLERS = %i[godot_30 default].freeze
|
8
|
+
|
9
|
+
# This class handle a Socket.
|
10
|
+
class Handler
|
11
|
+
attr_accessor :connection
|
12
|
+
|
13
|
+
def initialize(socket)
|
14
|
+
return if socket.nil?
|
15
|
+
|
16
|
+
@socket = socket
|
17
|
+
@thread = Thread.new do
|
18
|
+
begin
|
19
|
+
start
|
20
|
+
rescue StandardError => e
|
21
|
+
Kraken::Log.error e
|
22
|
+
close
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
def close
|
28
|
+
@connection.delete unless @connection.nil?
|
29
|
+
|
30
|
+
Kraken::Log.info 'bye bye socket'
|
31
|
+
|
32
|
+
@socket.close
|
33
|
+
@thread.kill
|
34
|
+
end
|
35
|
+
|
36
|
+
def read_trigger
|
37
|
+
trigger = read
|
38
|
+
args = read_args
|
39
|
+
[Kraken::Config.instance.triggers[trigger.downcase], args]
|
40
|
+
end
|
41
|
+
|
42
|
+
private
|
43
|
+
|
44
|
+
def start
|
45
|
+
version, user, pass = read_authentication_info
|
46
|
+
|
47
|
+
raise 'invalid version' unless Kraken::Config.instance.server_version == version
|
48
|
+
|
49
|
+
@connection = Connection.create(user: user, pass: pass)
|
50
|
+
@connection.save
|
51
|
+
|
52
|
+
raise 'only one connection by user' unless @connection.single_user?
|
53
|
+
|
54
|
+
if @connection.authenticate
|
55
|
+
write 'ok'
|
56
|
+
else
|
57
|
+
write 'nop'
|
58
|
+
raise 'can not authenticate'
|
59
|
+
end
|
60
|
+
|
61
|
+
work
|
62
|
+
close
|
63
|
+
end
|
64
|
+
|
65
|
+
def read_authentication_info
|
66
|
+
version = read
|
67
|
+
user = read
|
68
|
+
pass = read
|
69
|
+
[version, user, pass]
|
70
|
+
end
|
71
|
+
|
72
|
+
def work
|
73
|
+
loop do
|
74
|
+
trigger, args = read_trigger
|
75
|
+
|
76
|
+
shot = trigger.new(self, args)
|
77
|
+
shot.run
|
78
|
+
callback = shot.callback
|
79
|
+
|
80
|
+
write to_args(callback)
|
81
|
+
end
|
82
|
+
end
|
83
|
+
|
84
|
+
def read
|
85
|
+
r = @socket.gets
|
86
|
+
raise 'connection lost' if r.nil?
|
87
|
+
r.chomp
|
88
|
+
end
|
89
|
+
|
90
|
+
def read_args
|
91
|
+
type = read
|
92
|
+
case type
|
93
|
+
when 'h'
|
94
|
+
return read_hash
|
95
|
+
when 'v'
|
96
|
+
return read_vector
|
97
|
+
when 'n'
|
98
|
+
return nil
|
99
|
+
when 'a'
|
100
|
+
return read
|
101
|
+
end
|
102
|
+
end
|
103
|
+
|
104
|
+
def read_hash
|
105
|
+
n = read.to_i
|
106
|
+
awns = {}
|
107
|
+
n.times { awns[read.to_sym] = read_args }
|
108
|
+
awns
|
109
|
+
end
|
110
|
+
|
111
|
+
def read_vector
|
112
|
+
n = read.to_i
|
113
|
+
awns = []
|
114
|
+
n.times { awns << read_args }
|
115
|
+
awns
|
116
|
+
end
|
117
|
+
|
118
|
+
def write(txt)
|
119
|
+
@socket.puts txt.chomp
|
120
|
+
end
|
121
|
+
|
122
|
+
def to_args(obj)
|
123
|
+
case obj
|
124
|
+
when Hash
|
125
|
+
return "h\n#{obj.size}\n#{hash_protocol obj}"
|
126
|
+
when Array
|
127
|
+
return "v\n#{obj.size}\n#{vector_protocol obj}"
|
128
|
+
when NilClass
|
129
|
+
return 'n'
|
130
|
+
end
|
131
|
+
absolute_value(obj)
|
132
|
+
end
|
133
|
+
|
134
|
+
def hash_protocol(obj)
|
135
|
+
ret = ''
|
136
|
+
obj.each_pair { |key, value| ret += "#{key}\n#{to_args value}\n" }
|
137
|
+
ret.chomp
|
138
|
+
end
|
139
|
+
|
140
|
+
def vector_protocol(obj)
|
141
|
+
ret = ''
|
142
|
+
obj.each { |value| ret += "#{to_args value}\n" }
|
143
|
+
ret.chomp
|
144
|
+
end
|
145
|
+
|
146
|
+
def absolute_value(obj)
|
147
|
+
"a\n#{obj}"
|
148
|
+
end
|
149
|
+
end
|
150
|
+
end
|