interfacets 0.1.0 → 0.9.9
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 +4 -4
- data/.rubocop.yml +173 -1
- data/LICENSE +21 -0
- data/Rakefile +4 -6
- data/lib/interfacets/client/actor.rb +20 -0
- data/lib/interfacets/client/assets.rb +209 -0
- data/lib/interfacets/client/bus.rb +69 -0
- data/lib/interfacets/client/channels/api.rb +95 -0
- data/lib/interfacets/client/channels/audio.rb +101 -0
- data/lib/interfacets/client/channels/base.rb +28 -0
- data/lib/interfacets/client/channels/page_visibility.rb +21 -0
- data/lib/interfacets/client/channels/react/builder.rb +203 -0
- data/lib/interfacets/client/channels/react/channel.rb +61 -0
- data/lib/interfacets/client/channels/react/dom.rb +91 -0
- data/lib/interfacets/client/channels/react/evaluator.rb +33 -0
- data/lib/interfacets/client/channels/speech_to_text.rb +100 -0
- data/lib/interfacets/client/channels/timer.rb +51 -0
- data/lib/interfacets/client/channels/url.rb +52 -0
- data/lib/interfacets/client/config.rb +22 -0
- data/lib/interfacets/client/delegator.rb +37 -0
- data/lib/interfacets/client/facet.rb +26 -0
- data/lib/interfacets/client/facet2.rb +15 -0
- data/lib/interfacets/client/facets/attributes/accessor.rb +28 -0
- data/lib/interfacets/client/facets/attributes/association.rb +50 -0
- data/lib/interfacets/client/facets/attributes/bind.rb +25 -0
- data/lib/interfacets/client/facets/attributes/collection.rb +47 -0
- data/lib/interfacets/client/facets/attributes/readonly.rb +19 -0
- data/lib/interfacets/client/facets/deserializer.rb +30 -0
- data/lib/interfacets/client/facets/schema/deserializer.rb +63 -0
- data/lib/interfacets/client/facets/schema.rb +63 -0
- data/lib/interfacets/client/facets/serializer.rb +18 -0
- data/lib/interfacets/client/registry.rb +84 -0
- data/lib/interfacets/client/system.rb +88 -0
- data/lib/interfacets/client/utils/active_support_concern.rb +220 -0
- data/lib/interfacets/client/utils/mruby_patches.rb +81 -0
- data/lib/interfacets/client/utils/open_struct.rb +102 -0
- data/lib/interfacets/client/utils/securerandom.rb +69 -0
- data/lib/interfacets/client/view.rb +47 -0
- data/lib/interfacets/client.rb +13 -0
- data/lib/interfacets/mruby/build.dockerfile +66 -0
- data/lib/interfacets/mruby/build_config.rb +20 -0
- data/lib/interfacets/mruby/entrypoint.rb +23 -0
- data/lib/interfacets/mruby/init.c +66 -0
- data/lib/interfacets/server/api.rb +64 -0
- data/lib/interfacets/server/assets/facet.rb +61 -0
- data/lib/interfacets/server/assets.rb +210 -0
- data/lib/interfacets/server/basic_routable.rb +40 -0
- data/lib/interfacets/server/basic_router.rb +74 -0
- data/lib/interfacets/server/bus.rb +39 -0
- data/lib/interfacets/server/config.rb +87 -0
- data/lib/interfacets/server/facet.rb +51 -0
- data/lib/interfacets/server/facets/deserializer.rb +25 -0
- data/lib/interfacets/server/facets/schema/serializer.rb +54 -0
- data/lib/interfacets/server/facets/serializer.rb +50 -0
- data/lib/interfacets/server/registry.rb +212 -0
- data/lib/interfacets/shared/entities/bus.rb +218 -0
- data/lib/interfacets/shared/entities/collection_proxy.rb +190 -0
- data/lib/interfacets/shared/entities/specs/handlers.rb +117 -0
- data/lib/interfacets/shared/entities/specs.rb +124 -0
- data/lib/interfacets/shared/entity.rb +178 -0
- data/lib/interfacets/shared/entity_collection.rb +88 -0
- data/lib/interfacets/shared/generated_store.rb +145 -0
- data/lib/interfacets/shared/utils.rb +54 -0
- data/lib/interfacets/shared/validations.rb +71 -0
- data/lib/interfacets/test/browser.rb +63 -0
- data/lib/interfacets/test/js/inline_bus.rb +91 -0
- data/lib/interfacets/test/js/nodo_bus.rb +81 -0
- data/lib/interfacets/test/js/receivers/api.rb +37 -0
- data/lib/interfacets/test/js/receivers/react/node.rb +167 -0
- data/lib/interfacets/test/js/receivers/react.rb +31 -0
- data/lib/interfacets/test/js/receivers/url.rb +55 -0
- data/lib/interfacets/test.rb +17 -0
- data/lib/interfacets/version.rb +1 -1
- data/lib/interfacets.rb +26 -2
- metadata +103 -6
- data/README.md +0 -35
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: b1f88601fcc7349a9d14fb653aa28bd0fb988dce3571ea4c488d9ea0c46ece93
|
|
4
|
+
data.tar.gz: 8e954aa9c6b4c0d40fdf4df5487fcc0f4de2d36b6ff6e0abfcf446e321cc8e8d
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 0ad6edcb3b43786a4b914c18d0899ff3e4400ad039e92a11553f31e1d97dee3125a1bd9a58050bb4bb8f28db5d568ba00e0f9d9dfe6afd7ea71edc7b29e0ffb1
|
|
7
|
+
data.tar.gz: 163066c8f07e91d45351bf396473a6bd655db05d1b9bc792bad92c54fa9ac09d1aa4a1d4d68c59ddf03a8c8ef71e996c2e742bf2ad238ff72cb584697633998d
|
data/.rubocop.yml
CHANGED
|
@@ -1,8 +1,180 @@
|
|
|
1
1
|
AllCops:
|
|
2
|
-
|
|
2
|
+
NewCops: enable
|
|
3
|
+
Exclude: [ "bin/*" ]
|
|
4
|
+
|
|
5
|
+
Layout/EmptyLinesAroundAttributeAccessor:
|
|
6
|
+
Enabled: false
|
|
7
|
+
|
|
8
|
+
Layout/MultilineMethodCallBraceLayout:
|
|
9
|
+
Enabled: true
|
|
10
|
+
EnforcedStyle: new_line
|
|
11
|
+
|
|
12
|
+
Layout/MultilineMethodCallIndentation:
|
|
13
|
+
Enabled: true
|
|
14
|
+
EnforcedStyle: indented
|
|
15
|
+
|
|
16
|
+
Layout/MultilineMethodArgumentLineBreaks:
|
|
17
|
+
Enabled: true
|
|
18
|
+
|
|
19
|
+
Layout/MultilineMethodParameterLineBreaks:
|
|
20
|
+
Enabled: true
|
|
21
|
+
|
|
22
|
+
Layout/FirstMethodArgumentLineBreak:
|
|
23
|
+
Enabled: true
|
|
24
|
+
|
|
25
|
+
Layout/FirstMethodParameterLineBreak:
|
|
26
|
+
Enabled: true
|
|
27
|
+
|
|
28
|
+
Style/MethodCallWithArgsParentheses:
|
|
29
|
+
Enabled: true
|
|
30
|
+
|
|
31
|
+
Layout/ArgumentAlignment:
|
|
32
|
+
Enabled: true
|
|
33
|
+
EnforcedStyle: with_fixed_indentation
|
|
34
|
+
|
|
35
|
+
Lint/UnusedMethodArgument:
|
|
36
|
+
Enabled: false
|
|
37
|
+
|
|
38
|
+
Style/NumberedParameters:
|
|
39
|
+
Enabled: false
|
|
40
|
+
|
|
41
|
+
Style/OpenStructUse:
|
|
42
|
+
Enabled: false
|
|
43
|
+
|
|
44
|
+
Lint/EmptyBlock:
|
|
45
|
+
Enabled: false
|
|
46
|
+
|
|
47
|
+
Style/ExponentialNotation:
|
|
48
|
+
Enabled: false
|
|
49
|
+
|
|
50
|
+
Layout/MultilineAssignmentLayout:
|
|
51
|
+
Enabled: true
|
|
52
|
+
EnforcedStyle: new_line
|
|
53
|
+
|
|
54
|
+
Layout/ExtraSpacing:
|
|
55
|
+
Enabled: true
|
|
56
|
+
AllowForAlignment: false
|
|
57
|
+
|
|
58
|
+
Metrics/AbcSize:
|
|
59
|
+
Enabled: false
|
|
60
|
+
|
|
61
|
+
Metrics/BlockLength:
|
|
62
|
+
Enabled: false
|
|
63
|
+
|
|
64
|
+
Metrics/ClassLength:
|
|
65
|
+
Enabled: false
|
|
66
|
+
|
|
67
|
+
Metrics/CyclomaticComplexity:
|
|
68
|
+
Enabled: false
|
|
69
|
+
|
|
70
|
+
Metrics/MethodLength:
|
|
71
|
+
Enabled: false
|
|
72
|
+
|
|
73
|
+
Metrics/ModuleLength:
|
|
74
|
+
Enabled: false
|
|
75
|
+
|
|
76
|
+
Metrics/PerceivedComplexity:
|
|
77
|
+
Enabled: false
|
|
78
|
+
|
|
79
|
+
Naming/MethodParameterName:
|
|
80
|
+
Enabled: false
|
|
81
|
+
|
|
82
|
+
Naming/PredicateName:
|
|
83
|
+
Enabled: false
|
|
84
|
+
|
|
85
|
+
Naming/VariableNumber:
|
|
86
|
+
EnforcedStyle: snake_case
|
|
87
|
+
|
|
88
|
+
Security/Eval:
|
|
89
|
+
Enabled: false
|
|
90
|
+
|
|
91
|
+
Style/Alias:
|
|
92
|
+
Enabled: false
|
|
93
|
+
|
|
94
|
+
Style/BlockDelimiters:
|
|
95
|
+
Enabled: false
|
|
96
|
+
EnforcedStyle: semantic
|
|
97
|
+
|
|
98
|
+
Style/CaseLikeIf:
|
|
99
|
+
Enabled: false
|
|
100
|
+
|
|
101
|
+
Style/CombinableLoops:
|
|
102
|
+
Enabled: false
|
|
103
|
+
|
|
104
|
+
Style/Documentation:
|
|
105
|
+
Enabled: false
|
|
106
|
+
|
|
107
|
+
Style/EmptyLambdaParameter:
|
|
108
|
+
Enabled: false
|
|
109
|
+
|
|
110
|
+
Style/EvenOdd:
|
|
111
|
+
Enabled: false
|
|
112
|
+
|
|
113
|
+
|
|
114
|
+
Style/GuardClause:
|
|
115
|
+
Enabled: false
|
|
116
|
+
|
|
117
|
+
Style/IfUnlessModifier:
|
|
118
|
+
Enabled: false
|
|
119
|
+
|
|
120
|
+
Style/Lambda:
|
|
121
|
+
Enabled: false
|
|
122
|
+
|
|
123
|
+
Style/ModuleFunction:
|
|
124
|
+
Enabled: false
|
|
125
|
+
|
|
126
|
+
Style/MultilineBlockChain:
|
|
127
|
+
Enabled: false
|
|
128
|
+
|
|
129
|
+
Style/MultilineMemoization:
|
|
130
|
+
Enabled: true
|
|
131
|
+
EnforcedStyle: braces
|
|
132
|
+
|
|
133
|
+
Style/ParenthesesAroundCondition:
|
|
134
|
+
Enabled: true
|
|
135
|
+
AllowInMultilineConditions: true
|
|
136
|
+
|
|
137
|
+
Style/RaiseArgs:
|
|
138
|
+
Enabled: true
|
|
139
|
+
EnforcedStyle: compact
|
|
140
|
+
|
|
141
|
+
Style/RedundantParentheses:
|
|
142
|
+
Enabled: false
|
|
143
|
+
|
|
144
|
+
Style/RedundantSelf:
|
|
145
|
+
Enabled: false
|
|
3
146
|
|
|
4
147
|
Style/StringLiterals:
|
|
148
|
+
Enabled: true
|
|
5
149
|
EnforcedStyle: double_quotes
|
|
6
150
|
|
|
7
151
|
Style/StringLiteralsInInterpolation:
|
|
152
|
+
Enabled: true
|
|
8
153
|
EnforcedStyle: double_quotes
|
|
154
|
+
|
|
155
|
+
Style/SymbolArray:
|
|
156
|
+
Enabled: true
|
|
157
|
+
EnforcedStyle: brackets
|
|
158
|
+
|
|
159
|
+
Style/TrailingCommaInArguments:
|
|
160
|
+
Enabled: true
|
|
161
|
+
EnforcedStyleForMultiline: consistent_comma
|
|
162
|
+
|
|
163
|
+
Style/TrailingCommaInArrayLiteral:
|
|
164
|
+
Enabled: true
|
|
165
|
+
EnforcedStyleForMultiline: consistent_comma
|
|
166
|
+
|
|
167
|
+
Style/TrailingCommaInHashLiteral:
|
|
168
|
+
Enabled: true
|
|
169
|
+
EnforcedStyleForMultiline: consistent_comma
|
|
170
|
+
|
|
171
|
+
Style/WordArray:
|
|
172
|
+
Enabled: true
|
|
173
|
+
EnforcedStyle: brackets
|
|
174
|
+
|
|
175
|
+
Layout/LineLength:
|
|
176
|
+
Max: 100
|
|
177
|
+
AllowedPatterns: ['^(\s*#)']
|
|
178
|
+
|
|
179
|
+
Style/DocumentDynamicEvalDefinition:
|
|
180
|
+
Enabled: false
|
data/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2024 Pete Kinnecom
|
|
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 all
|
|
13
|
+
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 THE
|
|
21
|
+
SOFTWARE.
|
data/Rakefile
CHANGED
|
@@ -3,10 +3,8 @@
|
|
|
3
3
|
require "bundler/gem_tasks"
|
|
4
4
|
require "minitest/test_task"
|
|
5
5
|
|
|
6
|
-
Minitest::TestTask.create
|
|
6
|
+
Minitest::TestTask.create do |t|
|
|
7
|
+
t.warning = false
|
|
8
|
+
end
|
|
7
9
|
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
RuboCop::RakeTask.new
|
|
11
|
-
|
|
12
|
-
task default: %i[test rubocop]
|
|
10
|
+
task default: :test
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Interfacets
|
|
4
|
+
module Client
|
|
5
|
+
class Actor
|
|
6
|
+
attr_reader :registry, :facet
|
|
7
|
+
def initialize(registry:, channels:)
|
|
8
|
+
@registry = registry
|
|
9
|
+
end
|
|
10
|
+
|
|
11
|
+
def build_facet(name)
|
|
12
|
+
@facet = registry.build(name)
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
def render
|
|
16
|
+
facet.render(channels)
|
|
17
|
+
end
|
|
18
|
+
end
|
|
19
|
+
end
|
|
20
|
+
end
|
|
@@ -0,0 +1,209 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
# rubocop:disable Style/MissingRespondToMissing
|
|
4
|
+
original_verbose = $VERBOSE
|
|
5
|
+
$VERBOSE = nil
|
|
6
|
+
|
|
7
|
+
TOP_LEVEL_BINDING = self.binding
|
|
8
|
+
DEFAULT_LOG_LEVEL = ENV.fetch("DEFAULT_LOG_LEVEL", "debug").to_sym
|
|
9
|
+
|
|
10
|
+
class InterfacetsLogger
|
|
11
|
+
class << self
|
|
12
|
+
def main
|
|
13
|
+
@main ||= new(level: DEFAULT_LOG_LEVEL)
|
|
14
|
+
end
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
LEVELS = {
|
|
18
|
+
debug: 0,
|
|
19
|
+
info: 1,
|
|
20
|
+
warn: 2,
|
|
21
|
+
error: 3,
|
|
22
|
+
fatal: 4
|
|
23
|
+
}.freeze
|
|
24
|
+
|
|
25
|
+
attr_accessor :level
|
|
26
|
+
def initialize(level: :info)
|
|
27
|
+
@level = LEVELS[level] || LEVELS[:info]
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
# Meta-program the logging methods
|
|
31
|
+
LEVELS.each do |method_name, level_value|
|
|
32
|
+
define_method(method_name) do |message|
|
|
33
|
+
puts "#{method_name.to_s.upcase}: #{message}" if level_value >= @level
|
|
34
|
+
end
|
|
35
|
+
end
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
$VERBOSE = original_verbose
|
|
39
|
+
|
|
40
|
+
module Interfacets
|
|
41
|
+
module Client
|
|
42
|
+
module Assets
|
|
43
|
+
class << self
|
|
44
|
+
attr_reader :loader
|
|
45
|
+
|
|
46
|
+
def logger
|
|
47
|
+
$asset_logger ||= InterfacetsLogger.main
|
|
48
|
+
end
|
|
49
|
+
|
|
50
|
+
def bootstrap(assets)
|
|
51
|
+
@loader = Loader.new(assets)
|
|
52
|
+
Assets.logger.debug("bootstrapping")
|
|
53
|
+
|
|
54
|
+
assets
|
|
55
|
+
.fetch("scaffolding")
|
|
56
|
+
.reject { _1.match(/SecureRandom/) } #total hack, bake this into image
|
|
57
|
+
.join("\n")
|
|
58
|
+
.then { TOP_LEVEL_BINDING.eval(_1) }
|
|
59
|
+
|
|
60
|
+
Assets.logger.debug("done bootstrapping")
|
|
61
|
+
|
|
62
|
+
assets.fetch("fs_map").each_key do |path|
|
|
63
|
+
Assets.logger.debug("planned load: #{path}")
|
|
64
|
+
@loader.load_path(path)
|
|
65
|
+
end
|
|
66
|
+
end
|
|
67
|
+
end
|
|
68
|
+
|
|
69
|
+
class Loader
|
|
70
|
+
attr_reader :assets
|
|
71
|
+
def initialize(assets)
|
|
72
|
+
@assets = assets
|
|
73
|
+
@loaded_classes = {}
|
|
74
|
+
@loaded_paths = {}
|
|
75
|
+
end
|
|
76
|
+
|
|
77
|
+
def path_loaded?(path)
|
|
78
|
+
@loaded_paths.key?(path)
|
|
79
|
+
end
|
|
80
|
+
|
|
81
|
+
def load_path(path)
|
|
82
|
+
return if @loaded_paths.key?(path)
|
|
83
|
+
|
|
84
|
+
@loaded_paths[path] = true
|
|
85
|
+
|
|
86
|
+
Assets.logger.debug("loading: #{path}")
|
|
87
|
+
|
|
88
|
+
TOP_LEVEL_BINDING.eval(fs_map.fetch(path), path)
|
|
89
|
+
Assets.logger.debug("done loading: #{path}")
|
|
90
|
+
end
|
|
91
|
+
|
|
92
|
+
def loaded?(klass)
|
|
93
|
+
@loaded_classes.key?(klass)
|
|
94
|
+
end
|
|
95
|
+
|
|
96
|
+
def load(klass)
|
|
97
|
+
return if loaded?(klass)
|
|
98
|
+
|
|
99
|
+
@loaded_classes[klass] = true
|
|
100
|
+
|
|
101
|
+
return if klass.name.nil?
|
|
102
|
+
|
|
103
|
+
return unless const_map.key?(klass.name)
|
|
104
|
+
|
|
105
|
+
const_map
|
|
106
|
+
.fetch(klass.name)
|
|
107
|
+
.each {
|
|
108
|
+
Assets.logger.debug("klass caused load: #{_1}")
|
|
109
|
+
load_path(_1)
|
|
110
|
+
}
|
|
111
|
+
end
|
|
112
|
+
|
|
113
|
+
private
|
|
114
|
+
|
|
115
|
+
def scaffolding
|
|
116
|
+
@scaffolding ||= assets.fetch("scaffolding")
|
|
117
|
+
end
|
|
118
|
+
|
|
119
|
+
def fs_map
|
|
120
|
+
@fs_map ||= assets.fetch("fs_map")
|
|
121
|
+
end
|
|
122
|
+
|
|
123
|
+
def const_map
|
|
124
|
+
@const_map ||= assets.fetch("const_map")
|
|
125
|
+
end
|
|
126
|
+
end
|
|
127
|
+
|
|
128
|
+
module AutoloadHook
|
|
129
|
+
def extend_object(o)
|
|
130
|
+
if Assets.loader.loaded?(self)
|
|
131
|
+
super
|
|
132
|
+
else
|
|
133
|
+
Assets.loader.load(self)
|
|
134
|
+
send(:extend_object, o)
|
|
135
|
+
end
|
|
136
|
+
end
|
|
137
|
+
|
|
138
|
+
def inherited(mod)
|
|
139
|
+
if Assets.loader.loaded?(self)
|
|
140
|
+
super
|
|
141
|
+
else
|
|
142
|
+
Assets.loader.load(self)
|
|
143
|
+
send(:inherited, mod)
|
|
144
|
+
end
|
|
145
|
+
end
|
|
146
|
+
|
|
147
|
+
def append_features(mod)
|
|
148
|
+
if Assets.loader.loaded?(self)
|
|
149
|
+
super
|
|
150
|
+
else
|
|
151
|
+
Assets.loader.load(self)
|
|
152
|
+
send(:append_features, mod)
|
|
153
|
+
end
|
|
154
|
+
end
|
|
155
|
+
|
|
156
|
+
# def included(mod)
|
|
157
|
+
# Assets.logger.debug("included: #{self.name} into #{mod.name}")
|
|
158
|
+
# unless Assets.loader.loaded?(self)
|
|
159
|
+
# Assets.loader.load(self)
|
|
160
|
+
# send(:included, mod)
|
|
161
|
+
# else
|
|
162
|
+
# super
|
|
163
|
+
# end
|
|
164
|
+
# end
|
|
165
|
+
|
|
166
|
+
# def extended(mod)
|
|
167
|
+
# Assets.logger.debug("extended: #{mod.name}")
|
|
168
|
+
# unless Assets.loader.loaded?(self)
|
|
169
|
+
# Assets.logger.debug("loaded: #{self}, now extending")
|
|
170
|
+
# Assets.loader.load(self)
|
|
171
|
+
# send(:extended, mod)
|
|
172
|
+
# else
|
|
173
|
+
# Assets.logger.debug("already loaded: #{self}, not extending")
|
|
174
|
+
# super
|
|
175
|
+
# end
|
|
176
|
+
# end
|
|
177
|
+
|
|
178
|
+
# def prepended(mod)
|
|
179
|
+
# unless Assets.loader.loaded?(self)
|
|
180
|
+
# Assets.loader.load(self)
|
|
181
|
+
# send(:prepended, mod)
|
|
182
|
+
# else
|
|
183
|
+
# super
|
|
184
|
+
# end
|
|
185
|
+
# end
|
|
186
|
+
|
|
187
|
+
# don't think this is needed
|
|
188
|
+
# def const_missing(const_name)
|
|
189
|
+
# if Assets.loader.loaded?(self)
|
|
190
|
+
# super
|
|
191
|
+
# else
|
|
192
|
+
# Assets.loader.load(self)
|
|
193
|
+
# const_get(const_name)
|
|
194
|
+
# end
|
|
195
|
+
# end
|
|
196
|
+
|
|
197
|
+
def method_missing(meth, *a, **p, &)
|
|
198
|
+
if Assets.loader.loaded?(self)
|
|
199
|
+
super
|
|
200
|
+
else
|
|
201
|
+
Assets.loader.load(self)
|
|
202
|
+
send(meth, *a, **p, &)
|
|
203
|
+
end
|
|
204
|
+
end
|
|
205
|
+
end
|
|
206
|
+
end
|
|
207
|
+
end
|
|
208
|
+
end
|
|
209
|
+
# rubocop:enable Style/MissingRespondToMissing
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
# This pipes messages through channels. This allows channel authors to intercept
|
|
4
|
+
# and incoming and outgoing messages and dropping/ignoring/updating their own state
|
|
5
|
+
|
|
6
|
+
module Interfacets
|
|
7
|
+
module Client
|
|
8
|
+
class Bus
|
|
9
|
+
attr_reader(
|
|
10
|
+
:id,
|
|
11
|
+
:channels,
|
|
12
|
+
:channel_index,
|
|
13
|
+
:registry,
|
|
14
|
+
:entity,
|
|
15
|
+
:root_url,
|
|
16
|
+
)
|
|
17
|
+
|
|
18
|
+
def initialize(
|
|
19
|
+
id:,
|
|
20
|
+
channels:,
|
|
21
|
+
root_url:
|
|
22
|
+
)
|
|
23
|
+
@id = id
|
|
24
|
+
@channels = channels
|
|
25
|
+
@registry = Registry.new
|
|
26
|
+
@channel_index = channels.map { [_1.id, _1] }.to_h
|
|
27
|
+
@root_url = root_url
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
def url_for(path)
|
|
31
|
+
[
|
|
32
|
+
root_url,
|
|
33
|
+
path,
|
|
34
|
+
]
|
|
35
|
+
.map { _1.sub(%r{/$}, "").sub(%r{^/}, "") }
|
|
36
|
+
.join("/")
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
def channel(name)
|
|
40
|
+
channel_index.fetch(name.to_s)
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
def handle(event)
|
|
44
|
+
channel_id = event.dig("destination", "channel")
|
|
45
|
+
raise("unknown event: #{event.inspect}") unless channel_id
|
|
46
|
+
channel = channel_index.fetch(channel_id)
|
|
47
|
+
|
|
48
|
+
channel.handle(
|
|
49
|
+
entity: @entity,
|
|
50
|
+
event: event.fetch("payload"),
|
|
51
|
+
build_entity: ->(name) { @entity = registry.build(name) }
|
|
52
|
+
)
|
|
53
|
+
|
|
54
|
+
channel_index.values.each { _1.prepare(entity) }
|
|
55
|
+
|
|
56
|
+
entity.class.view.new.render(entity:, channels: channel_index)
|
|
57
|
+
|
|
58
|
+
{
|
|
59
|
+
type: "interfacets:bus:render",
|
|
60
|
+
id: id,
|
|
61
|
+
payload: (
|
|
62
|
+
channel_index
|
|
63
|
+
.map { |name, chann| { id: name, payload: chann.result } }
|
|
64
|
+
)
|
|
65
|
+
}
|
|
66
|
+
end
|
|
67
|
+
end
|
|
68
|
+
end
|
|
69
|
+
end
|
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Interfacets
|
|
4
|
+
module Client
|
|
5
|
+
module Channels
|
|
6
|
+
class Api
|
|
7
|
+
include Channels::Base
|
|
8
|
+
|
|
9
|
+
class Builder
|
|
10
|
+
attr_accessor :request, :entity
|
|
11
|
+
|
|
12
|
+
def render(path)
|
|
13
|
+
raise("only one submission per action") if request
|
|
14
|
+
|
|
15
|
+
System.logger.debug("Getting #{path}")
|
|
16
|
+
|
|
17
|
+
request_id = SecureRandom.uuid
|
|
18
|
+
|
|
19
|
+
self.request = {
|
|
20
|
+
url: Client::System.current_bus.url_for(path),
|
|
21
|
+
method: "get",
|
|
22
|
+
}
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
def submit(meth)
|
|
26
|
+
raise("only one submission per action") if request
|
|
27
|
+
|
|
28
|
+
System.logger.debug("submitting #{meth}")
|
|
29
|
+
|
|
30
|
+
request_id = SecureRandom.uuid
|
|
31
|
+
|
|
32
|
+
self.request = {
|
|
33
|
+
url: (
|
|
34
|
+
if entity.respond_to?(:api_path)
|
|
35
|
+
Client::System.current_bus.url_for(entity.api_path)
|
|
36
|
+
end
|
|
37
|
+
),
|
|
38
|
+
method: "put",
|
|
39
|
+
body: {
|
|
40
|
+
event: {
|
|
41
|
+
id: request_id,
|
|
42
|
+
type: "interfacets:api:submit",
|
|
43
|
+
payload: (
|
|
44
|
+
Shared::Entities::Bus
|
|
45
|
+
.new(entity:)
|
|
46
|
+
.serialize(
|
|
47
|
+
to: "server" ,
|
|
48
|
+
action: meth,
|
|
49
|
+
nesting: ["root"]
|
|
50
|
+
)
|
|
51
|
+
)
|
|
52
|
+
},
|
|
53
|
+
},
|
|
54
|
+
}
|
|
55
|
+
end
|
|
56
|
+
end
|
|
57
|
+
|
|
58
|
+
type("interfacets:api")
|
|
59
|
+
|
|
60
|
+
def prepare(entity)
|
|
61
|
+
# must persist builder here
|
|
62
|
+
# probably all channels need to persist their
|
|
63
|
+
# builder. Because the bus calls "handle" before
|
|
64
|
+
# the "prepare" call. Perhaps these should be
|
|
65
|
+
# reversed?
|
|
66
|
+
@builder ||= Builder.new
|
|
67
|
+
@builder.entity = entity
|
|
68
|
+
end
|
|
69
|
+
|
|
70
|
+
def builder(stream = "default")
|
|
71
|
+
@builder
|
|
72
|
+
end
|
|
73
|
+
|
|
74
|
+
def result
|
|
75
|
+
{
|
|
76
|
+
streams: {
|
|
77
|
+
default: @builder.request,
|
|
78
|
+
},
|
|
79
|
+
}.tap { @builder.request = nil }
|
|
80
|
+
end
|
|
81
|
+
|
|
82
|
+
def handle(event:, entity:, build_entity:)
|
|
83
|
+
facet_name = event.fetch("facet")
|
|
84
|
+
entity = build_entity.(facet_name)
|
|
85
|
+
|
|
86
|
+
Shared::Entities::Bus
|
|
87
|
+
.new(entity:)
|
|
88
|
+
.handle(
|
|
89
|
+
event: event.fetch("payload")
|
|
90
|
+
)
|
|
91
|
+
end
|
|
92
|
+
end
|
|
93
|
+
end
|
|
94
|
+
end
|
|
95
|
+
end
|