cosmos 5.0.2.pre.beta2 → 5.0.4
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/bin/cosmos +1 -1
- data/data/config/microservice.yaml +47 -35
- data/data/config/plugins.yaml +3 -150
- data/data/config/target.yaml +70 -0
- data/data/config/tool.yaml +37 -31
- data/lib/cosmos/api/api.rb +1 -25
- data/lib/cosmos/api/cmd_api.rb +17 -6
- data/lib/cosmos/api/config_api.rb +10 -4
- data/lib/cosmos/api/limits_api.rb +1 -1
- data/lib/cosmos/api/settings_api.rb +19 -7
- data/lib/cosmos/api/target_api.rb +2 -2
- data/lib/cosmos/api/tlm_api.rb +69 -41
- data/lib/cosmos/config/config_parser.rb +19 -22
- data/lib/cosmos/config/meta_config_parser.rb +1 -1
- data/lib/cosmos/conversions/generic_conversion.rb +2 -2
- data/lib/cosmos/conversions/polynomial_conversion.rb +5 -8
- data/lib/cosmos/conversions/segmented_polynomial_conversion.rb +26 -9
- data/lib/cosmos/io/json_drb.rb +5 -1
- data/lib/cosmos/logs/log_writer.rb +2 -2
- data/lib/cosmos/microservices/cleanup_microservice.rb +28 -29
- data/lib/cosmos/microservices/decom_microservice.rb +1 -1
- data/lib/cosmos/microservices/interface_microservice.rb +0 -1
- data/lib/cosmos/microservices/microservice.rb +3 -3
- data/lib/cosmos/microservices/reducer_microservice.rb +12 -10
- data/lib/cosmos/models/cvt_model.rb +6 -6
- data/lib/cosmos/models/gem_model.rb +3 -3
- data/lib/cosmos/models/info_model.rb +1 -1
- data/lib/cosmos/models/interface_status_model.rb +1 -1
- data/lib/cosmos/models/metadata_model.rb +42 -216
- data/lib/cosmos/models/metric_model.rb +2 -2
- data/lib/cosmos/models/microservice_model.rb +1 -1
- data/lib/cosmos/models/microservice_status_model.rb +1 -1
- data/lib/cosmos/models/model.rb +16 -16
- data/lib/cosmos/models/note_model.rb +124 -0
- data/lib/cosmos/models/ping_model.rb +2 -1
- data/lib/cosmos/models/plugin_model.rb +1 -1
- data/lib/cosmos/models/process_status_model.rb +1 -1
- data/lib/cosmos/models/scope_model.rb +9 -26
- data/lib/cosmos/models/settings_model.rb +55 -0
- data/lib/cosmos/models/sorted_model.rb +165 -0
- data/lib/cosmos/models/target_model.rb +120 -13
- data/lib/cosmos/models/tool_config_model.rb +38 -0
- data/lib/cosmos/models/tool_model.rb +1 -1
- data/lib/cosmos/models/widget_model.rb +1 -1
- data/lib/cosmos/operators/microservice_operator.rb +2 -1
- data/lib/cosmos/packets/packet.rb +23 -0
- data/lib/cosmos/packets/packet_config.rb +2 -2
- data/lib/cosmos/packets/packet_item.rb +57 -0
- data/lib/cosmos/packets/packet_item_limits.rb +14 -2
- data/lib/cosmos/packets/parsers/packet_item_parser.rb +1 -1
- data/lib/cosmos/packets/parsers/packet_parser.rb +1 -1
- data/lib/cosmos/packets/parsers/xtce_parser.rb +1 -1
- data/lib/cosmos/packets/structure_item.rb +10 -1
- data/lib/cosmos/script/api_shared.rb +30 -25
- data/lib/cosmos/script/calendar.rb +26 -15
- data/lib/cosmos/script/commands.rb +5 -7
- data/lib/cosmos/script/script.rb +19 -39
- data/lib/cosmos/script/storage.rb +92 -105
- data/lib/cosmos/system/system.rb +2 -1
- data/lib/cosmos/tools/table_manager/table_item.rb +1 -1
- data/lib/cosmos/top_level.rb +5 -1
- data/lib/cosmos/topics/autonomic_topic.rb +2 -2
- data/lib/cosmos/topics/calendar_topic.rb +1 -1
- data/lib/cosmos/topics/command_decom_topic.rb +35 -1
- data/lib/cosmos/topics/command_topic.rb +6 -4
- data/lib/cosmos/topics/interface_topic.rb +8 -8
- data/lib/cosmos/topics/limits_event_topic.rb +5 -3
- data/lib/cosmos/topics/notifications_topic.rb +1 -1
- data/lib/cosmos/topics/router_topic.rb +9 -9
- data/lib/cosmos/topics/telemetry_decom_topic.rb +5 -1
- data/lib/cosmos/topics/telemetry_topic.rb +1 -1
- data/lib/cosmos/topics/timeline_topic.rb +1 -1
- data/lib/cosmos/topics/topic.rb +23 -8
- data/lib/cosmos/utilities/logger.rb +4 -3
- data/lib/cosmos/utilities/metric.rb +32 -26
- data/lib/cosmos/utilities/s3.rb +61 -0
- data/lib/cosmos/utilities/s3_file_cache.rb +12 -6
- data/lib/cosmos/utilities/store.rb +1 -0
- data/lib/cosmos/utilities/store_autoload.rb +25 -134
- data/lib/cosmos/version.rb +6 -5
- data/templates/plugin-template/plugin.gemspec +0 -2
- metadata +9 -6
- data/lib/cosmos/models/narrative_model.rb +0 -280
@@ -0,0 +1,124 @@
|
|
1
|
+
# encoding: ascii-8bit
|
2
|
+
|
3
|
+
# Copyright 2022 Ball Aerospace & Technologies Corp.
|
4
|
+
# All Rights Reserved.
|
5
|
+
#
|
6
|
+
# This program is free software; you can modify and/or redistribute it
|
7
|
+
# under the terms of the GNU Affero General Public License
|
8
|
+
# as published by the Free Software Foundation; version 3 with
|
9
|
+
# attribution addendums as found in the LICENSE.txt
|
10
|
+
#
|
11
|
+
# This program is distributed in the hope that it will be useful,
|
12
|
+
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
13
|
+
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
14
|
+
# GNU Affero General Public License for more details.
|
15
|
+
#
|
16
|
+
# This program may also be used under the terms of a commercial or
|
17
|
+
# enterprise edition license of COSMOS if purchased from the
|
18
|
+
# copyright holder
|
19
|
+
|
20
|
+
# https://www.rubydoc.info/gems/redis/Redis/Commands/SortedSets
|
21
|
+
|
22
|
+
require 'cosmos/models/sorted_model'
|
23
|
+
|
24
|
+
module Cosmos
|
25
|
+
class NoteModel < SortedModel
|
26
|
+
NOTE_TYPE = 'note'.freeze
|
27
|
+
PRIMARY_KEY = '__NOTE'.freeze
|
28
|
+
|
29
|
+
def self.pk(scope)
|
30
|
+
"#{scope}#{PRIMARY_KEY}"
|
31
|
+
end
|
32
|
+
|
33
|
+
attr_reader :stop, :color, :description, :type
|
34
|
+
|
35
|
+
# @param [String] scope - Cosmos scope to track event to
|
36
|
+
# @param [Integer] start - start of the event in seconds from Epoch
|
37
|
+
# @param [Integer] stop - stop of the event in seconds from Epoch
|
38
|
+
# @param [String] color - The event color
|
39
|
+
# @param [String] description - What the event is about
|
40
|
+
def initialize(
|
41
|
+
scope:,
|
42
|
+
start:,
|
43
|
+
stop:,
|
44
|
+
color: nil,
|
45
|
+
description:,
|
46
|
+
type: NOTE_TYPE,
|
47
|
+
updated_at: 0
|
48
|
+
)
|
49
|
+
super(start: start, scope: scope, updated_at: updated_at)
|
50
|
+
@start = start
|
51
|
+
@stop = stop
|
52
|
+
@color = color
|
53
|
+
@description = description
|
54
|
+
@type = type # For the as_json, from_json round trip
|
55
|
+
end
|
56
|
+
|
57
|
+
# Validates the instance variables: @start, @stop, @color, @description
|
58
|
+
def validate(update: false)
|
59
|
+
validate_start(update: update)
|
60
|
+
validate_stop()
|
61
|
+
validate_color()
|
62
|
+
end
|
63
|
+
|
64
|
+
def validate_stop()
|
65
|
+
unless @stop.is_a?(Integer)
|
66
|
+
raise SortedInputError.new "stop must be integer: #{@stop}"
|
67
|
+
end
|
68
|
+
if @stop.to_i < @start
|
69
|
+
raise SortedInputError.new "stop: #{@stop} must be >= start: #{@start}"
|
70
|
+
end
|
71
|
+
@stop = @stop.to_i
|
72
|
+
end
|
73
|
+
|
74
|
+
def validate_color()
|
75
|
+
if @color.nil?
|
76
|
+
@color = '#%06x' % (rand * 0xffffff)
|
77
|
+
end
|
78
|
+
unless @color =~ /(#*)([0-9,a-f,A-f]{6})/
|
79
|
+
raise SortedInputError.new "invalid color, must be in hex format, e.g. #FF0000"
|
80
|
+
end
|
81
|
+
@color = "##{@color}" unless @color.start_with?('#')
|
82
|
+
end
|
83
|
+
|
84
|
+
# Update the Redis hash at primary_key based on the initial passed start
|
85
|
+
# The member is set to the JSON generated via calling as_json
|
86
|
+
def create(update: false)
|
87
|
+
validate(update: update)
|
88
|
+
@updated_at = Time.now.to_nsec_from_epoch
|
89
|
+
Store.zadd(@primary_key, @start, JSON.generate(as_json()))
|
90
|
+
if update
|
91
|
+
notify(kind: 'updated')
|
92
|
+
else
|
93
|
+
notify(kind: 'created')
|
94
|
+
end
|
95
|
+
end
|
96
|
+
|
97
|
+
# Update the Redis hash at primary_key
|
98
|
+
def update(start:, stop:, color:, description:)
|
99
|
+
@start = start
|
100
|
+
@stop = stop
|
101
|
+
@color = color
|
102
|
+
@description = description
|
103
|
+
create(update: true)
|
104
|
+
end
|
105
|
+
|
106
|
+
# @return [Hash] generated from the NoteModel
|
107
|
+
def as_json
|
108
|
+
return {
|
109
|
+
'scope' => @scope,
|
110
|
+
'start' => @start,
|
111
|
+
'stop' => @stop,
|
112
|
+
'color' => @color,
|
113
|
+
'description' => @description,
|
114
|
+
'type' => NOTE_TYPE,
|
115
|
+
'updated_at' => @updated_at,
|
116
|
+
}
|
117
|
+
end
|
118
|
+
|
119
|
+
# @return [String] string view of NoteModel
|
120
|
+
def to_s
|
121
|
+
return "<NoteModel s: #{@start}, x: #{@stop}, c: #{@color}, d: #{@description}>"
|
122
|
+
end
|
123
|
+
end
|
124
|
+
end
|
@@ -125,7 +125,7 @@ module Cosmos
|
|
125
125
|
gem_file_path = Cosmos::GemModel.get(temp_dir, name)
|
126
126
|
|
127
127
|
# Actually install the gem now (slow)
|
128
|
-
Cosmos::GemModel.install(gem_file_path)
|
128
|
+
Cosmos::GemModel.install(gem_file_path, scope: scope)
|
129
129
|
|
130
130
|
# Extract gem contents
|
131
131
|
gem_path = File.join(temp_dir, "gem")
|
@@ -20,6 +20,7 @@
|
|
20
20
|
require 'cosmos/version'
|
21
21
|
require 'cosmos/models/model'
|
22
22
|
require 'cosmos/models/microservice_model'
|
23
|
+
require 'cosmos/models/settings_model'
|
23
24
|
|
24
25
|
module Cosmos
|
25
26
|
class ScopeModel < Model
|
@@ -51,24 +52,6 @@ module Cosmos
|
|
51
52
|
def deploy(gem_path, variables)
|
52
53
|
seed_database()
|
53
54
|
|
54
|
-
# Cleanup Microservice
|
55
|
-
microservice_name = "#{@scope}__CLEANUP__S3"
|
56
|
-
microservice = MicroserviceModel.new(
|
57
|
-
name: microservice_name,
|
58
|
-
cmd: ["ruby", "cleanup_microservice.rb", microservice_name],
|
59
|
-
work_dir: '/cosmos/lib/cosmos/microservices',
|
60
|
-
options: [
|
61
|
-
["SIZE", "20_000_000_000"], # Max Size to keep in S3
|
62
|
-
["DELAY", "300"], # Delay between size checks
|
63
|
-
["BUCKET", "logs"], # Bucket to monitor
|
64
|
-
["PREFIX", @scope + "/"], # Path into bucket to monitor
|
65
|
-
],
|
66
|
-
scope: @scope
|
67
|
-
)
|
68
|
-
microservice.create
|
69
|
-
microservice.deploy(gem_path, variables)
|
70
|
-
Logger.info "Configured microservice #{microservice_name}"
|
71
|
-
|
72
55
|
# COSMOS Log Microservice
|
73
56
|
microservice_name = "#{@scope}__COSMOS__LOG"
|
74
57
|
microservice = MicroserviceModel.new(
|
@@ -105,7 +88,7 @@ module Cosmos
|
|
105
88
|
Logger.info "Configured microservice #{microservice_name}"
|
106
89
|
|
107
90
|
# UNKNOWN CommandLog Microservice
|
108
|
-
|
91
|
+
Topic.initialize_streams(["#{@scope}__COMMAND__{UNKNOWN}__UNKNOWN"])
|
109
92
|
microservice_name = "#{@scope}__COMMANDLOG__UNKNOWN"
|
110
93
|
microservice = MicroserviceModel.new(
|
111
94
|
name: microservice_name,
|
@@ -125,7 +108,7 @@ module Cosmos
|
|
125
108
|
Logger.info "Configured microservice #{microservice_name}"
|
126
109
|
|
127
110
|
# UNKNOWN PacketLog Microservice
|
128
|
-
|
111
|
+
Topic.initialize_streams(["#{@scope}__TELEMETRY__{UNKNOWN}__UNKNOWN"])
|
129
112
|
microservice_name = "#{@scope}__PACKETLOG__UNKNOWN"
|
130
113
|
microservice = MicroserviceModel.new(
|
131
114
|
name: microservice_name,
|
@@ -146,8 +129,6 @@ module Cosmos
|
|
146
129
|
end
|
147
130
|
|
148
131
|
def undeploy
|
149
|
-
model = MicroserviceModel.get_model(name: "#{@scope}__CLEANUP__S3", scope: @scope)
|
150
|
-
model.destroy if model
|
151
132
|
model = MicroserviceModel.get_model(name: "#{@scope}__COSMOS__LOG", scope: @scope)
|
152
133
|
model.destroy if model
|
153
134
|
model = MicroserviceModel.get_model(name: "#{@scope}__NOTIFICATION__LOG", scope: @scope)
|
@@ -159,10 +140,12 @@ module Cosmos
|
|
159
140
|
end
|
160
141
|
|
161
142
|
def seed_database
|
162
|
-
|
163
|
-
|
164
|
-
|
165
|
-
|
143
|
+
setting = SettingsModel.get(name: 'source_url')
|
144
|
+
SettingsModel.set({ name: 'source_url', data: 'https://github.com/BallAerospace/COSMOS' }, scope: @scope) unless setting
|
145
|
+
end
|
146
|
+
|
147
|
+
def self.limits_set(scope:)
|
148
|
+
Store.hget("#{scope}__cosmos_system", 'limits_set').intern
|
166
149
|
end
|
167
150
|
end
|
168
151
|
end
|
@@ -0,0 +1,55 @@
|
|
1
|
+
# encoding: ascii-8bit
|
2
|
+
|
3
|
+
# Copyright 2022 Ball Aerospace & Technologies Corp.
|
4
|
+
# All Rights Reserved.
|
5
|
+
#
|
6
|
+
# This program is free software; you can modify and/or redistribute it
|
7
|
+
# under the terms of the GNU Affero General Public License
|
8
|
+
# as published by the Free Software Foundation; version 3 with
|
9
|
+
# attribution addendums as found in the LICENSE.txt
|
10
|
+
#
|
11
|
+
# This program is distributed in the hope that it will be useful,
|
12
|
+
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
13
|
+
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
14
|
+
# GNU Affero General Public License for more details.
|
15
|
+
#
|
16
|
+
# This program may also be used under the terms of a commercial or
|
17
|
+
# enterprise edition license of COSMOS if purchased from the
|
18
|
+
# copyright holder
|
19
|
+
|
20
|
+
require 'cosmos/models/model'
|
21
|
+
|
22
|
+
module Cosmos
|
23
|
+
class SettingsModel < Model
|
24
|
+
PRIMARY_KEY = 'cosmos__settings'
|
25
|
+
|
26
|
+
# NOTE: The following three class methods are used by the ModelController
|
27
|
+
# and are reimplemented to enable various Model class methods to work
|
28
|
+
def self.get(name:, scope: nil)
|
29
|
+
super(PRIMARY_KEY, name: name)
|
30
|
+
end
|
31
|
+
|
32
|
+
def self.names(scope: nil)
|
33
|
+
super(PRIMARY_KEY)
|
34
|
+
end
|
35
|
+
|
36
|
+
def self.all(scope: nil)
|
37
|
+
super(PRIMARY_KEY)
|
38
|
+
end
|
39
|
+
# END NOTE
|
40
|
+
|
41
|
+
def initialize(name:, scope: nil, data:)
|
42
|
+
super(PRIMARY_KEY, name: name, scope: scope)
|
43
|
+
@data = data
|
44
|
+
end
|
45
|
+
|
46
|
+
# @return [Hash] JSON encoding of this model
|
47
|
+
def as_json
|
48
|
+
{
|
49
|
+
'name' => @name,
|
50
|
+
'data' => @data,
|
51
|
+
'updated_at' => @updated_at
|
52
|
+
}
|
53
|
+
end
|
54
|
+
end
|
55
|
+
end
|
@@ -0,0 +1,165 @@
|
|
1
|
+
# encoding: ascii-8bit
|
2
|
+
|
3
|
+
# Copyright 2022 Ball Aerospace & Technologies Corp.
|
4
|
+
# All Rights Reserved.
|
5
|
+
#
|
6
|
+
# This program is free software; you can modify and/or redistribute it
|
7
|
+
# under the terms of the GNU Affero General Public License
|
8
|
+
# as published by the Free Software Foundation; version 3 with
|
9
|
+
# attribution addendums as found in the LICENSE.txt
|
10
|
+
#
|
11
|
+
# This program is distributed in the hope that it will be useful,
|
12
|
+
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
13
|
+
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
14
|
+
# GNU Affero General Public License for more details.
|
15
|
+
#
|
16
|
+
# This program may also be used under the terms of a commercial or
|
17
|
+
# enterprise edition license of COSMOS if purchased from the
|
18
|
+
# copyright holder
|
19
|
+
|
20
|
+
# https://www.rubydoc.info/gems/redis/Redis/Commands/SortedSets
|
21
|
+
# https://redis.io/docs/manual/data-types/data-types-tutorial/#sorted-sets
|
22
|
+
|
23
|
+
require 'cosmos/models/model'
|
24
|
+
require 'cosmos/topics/calendar_topic'
|
25
|
+
|
26
|
+
module Cosmos
|
27
|
+
# Put these under the Cosmos module so they are easily accessed in the controller as
|
28
|
+
# Cosmos::SortedError vs Cosmos::SortedModel::Error
|
29
|
+
class SortedError < StandardError; end
|
30
|
+
class SortedInputError < SortedError; end
|
31
|
+
class SortedOverlapError < SortedError; end
|
32
|
+
|
33
|
+
class SortedModel < Model
|
34
|
+
SORTED_TYPE = 'sorted'.freeze # To be overriden by base class
|
35
|
+
PRIMARY_KEY = '__SORTED'.freeze # To be overriden by base class
|
36
|
+
|
37
|
+
# MUST be overriden by any subclasses
|
38
|
+
def self.pk(scope)
|
39
|
+
"#{scope}#{PRIMARY_KEY}"
|
40
|
+
end
|
41
|
+
|
42
|
+
# @return [String|nil] String of the saved json or nil if start not found
|
43
|
+
def self.get(start:, scope:)
|
44
|
+
result = Store.zrangebyscore(self.pk(scope), start, start)
|
45
|
+
return JSON.parse(result[0]) unless result.empty?
|
46
|
+
nil
|
47
|
+
end
|
48
|
+
|
49
|
+
# @return [Array<Hash>] Array up to the limit of the models (as Hash objects) stored under the primary key
|
50
|
+
def self.all(scope:, limit: 100)
|
51
|
+
result = Store.zrevrangebyscore(self.pk(scope), '+inf', '-inf', limit: [0, limit])
|
52
|
+
result.map { |item| JSON.parse(item) }
|
53
|
+
end
|
54
|
+
|
55
|
+
# @return [String|nil] json or nil if metadata empty
|
56
|
+
def self.get_current_value(scope:)
|
57
|
+
start = Time.now.to_i
|
58
|
+
array = Store.zrevrangebyscore(self.pk(scope), start, '-inf', limit: [0, 1])
|
59
|
+
return nil if array.empty?
|
60
|
+
return array[0]
|
61
|
+
end
|
62
|
+
|
63
|
+
# @param start [Integer] Start time to return values (inclusive)
|
64
|
+
# @param stop [Integer] Stop time to return values (inclusive)
|
65
|
+
# @return [Array|nil] Array up to 100 of this model or empty array
|
66
|
+
def self.range(start:, stop:, scope:, limit: 100)
|
67
|
+
if start > stop
|
68
|
+
raise SortedInputError.new "start: #{start} must be before stop: #{stop}"
|
69
|
+
end
|
70
|
+
result = Store.zrangebyscore(self.pk(scope), start, stop, limit: [0, limit])
|
71
|
+
result.map { |item| JSON.parse(item) }
|
72
|
+
end
|
73
|
+
|
74
|
+
# @return [Integer] count of the members stored under the primary key
|
75
|
+
def self.count(scope:)
|
76
|
+
Store.zcard(self.pk(scope))
|
77
|
+
end
|
78
|
+
|
79
|
+
# Remove member from a sorted set
|
80
|
+
# @return [Integer] count of the members removed, 0 if not found
|
81
|
+
def self.destroy(scope:, start:)
|
82
|
+
Store.zremrangebyscore(self.pk(scope), start, start)
|
83
|
+
end
|
84
|
+
|
85
|
+
# Remove members from min to max of the sorted set.
|
86
|
+
# @return [Integer] count of the members removed
|
87
|
+
def self.range_destroy(scope:, start:, stop:)
|
88
|
+
Store.zremrangebyscore(self.pk(scope), start, stop)
|
89
|
+
end
|
90
|
+
|
91
|
+
attr_reader :start
|
92
|
+
|
93
|
+
# @param [Integer] start - start used to store data
|
94
|
+
# @param [String] scope - Cosmos scope to track event to
|
95
|
+
# @param [Anything] kwargs - Any kwargs to store in the JSON
|
96
|
+
def initialize(start:, scope:, type: SORTED_TYPE, **kwargs)
|
97
|
+
# Name becomes the start in the base class
|
98
|
+
super(self.class.pk(scope), name: start.to_s, scope: scope, **kwargs)
|
99
|
+
@type = type # For the as_json, from_json round trip
|
100
|
+
@start = start
|
101
|
+
end
|
102
|
+
|
103
|
+
# start MUST be a positive integer
|
104
|
+
def validate_start(update: false)
|
105
|
+
unless @start.is_a?(Integer)
|
106
|
+
raise SortedInputError.new "start must be integer: #{@start}"
|
107
|
+
end
|
108
|
+
if @start.to_i < 0
|
109
|
+
raise SortedInputError.new "start must be positive: #{@start}"
|
110
|
+
end
|
111
|
+
if !update and self.class.get(start: @start, scope: @scope)
|
112
|
+
raise SortedOverlapError.new "duplicate, existing data at #{@start}"
|
113
|
+
end
|
114
|
+
@start = @start.to_i
|
115
|
+
end
|
116
|
+
|
117
|
+
# Update the Redis hash at primary_key based on the initial passed start
|
118
|
+
# The member is set to the JSON generated via calling as_json
|
119
|
+
def create(update: false)
|
120
|
+
validate_start(update: update)
|
121
|
+
@updated_at = Time.now.to_nsec_from_epoch
|
122
|
+
Store.zadd(@primary_key, @start, JSON.generate(as_json()))
|
123
|
+
if update
|
124
|
+
notify(kind: 'updated')
|
125
|
+
else
|
126
|
+
notify(kind: 'created')
|
127
|
+
end
|
128
|
+
end
|
129
|
+
|
130
|
+
# Update the Redis hash at primary_key
|
131
|
+
def update(start:)
|
132
|
+
@start = start
|
133
|
+
create(update: true)
|
134
|
+
end
|
135
|
+
|
136
|
+
# destroy the activity from the redis database
|
137
|
+
def destroy
|
138
|
+
self.class.destroy(scope: @scope, start: @start)
|
139
|
+
notify(kind: 'deleted')
|
140
|
+
end
|
141
|
+
|
142
|
+
# @return [] update the redis stream / timeline topic that something has changed
|
143
|
+
def notify(kind:, extra: nil)
|
144
|
+
notification = {
|
145
|
+
'data' => JSON.generate(as_json()),
|
146
|
+
'kind' => kind,
|
147
|
+
'type' => 'calendar',
|
148
|
+
}
|
149
|
+
notification['extra'] = extra unless extra.nil?
|
150
|
+
begin
|
151
|
+
CalendarTopic.write_entry(notification, scope: @scope)
|
152
|
+
rescue StandardError => e
|
153
|
+
raise SortedError.new "Failed to write to stream: #{notification}, #{e}"
|
154
|
+
end
|
155
|
+
end
|
156
|
+
|
157
|
+
# @return [Hash] JSON encoding of this model
|
158
|
+
def as_json
|
159
|
+
{ **super(),
|
160
|
+
'start' => @start,
|
161
|
+
'type' => SORTED_TYPE,
|
162
|
+
}
|
163
|
+
end
|
164
|
+
end
|
165
|
+
end
|