krakenlab 2018.01.07
Sign up to get free protection for your applications and to get access to all the features.
- 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
|