Skip to content

Commit 8d6ac47

Browse files
committed
add drivers controller
1 parent 7d7f77c commit 8d6ac47

6 files changed

Lines changed: 67 additions & 64 deletions

File tree

shard.lock

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ shards:
77

88
action-controller:
99
git: https://github.com/spider-gazelle/action-controller.git
10-
version: 5.4.0
10+
version: 5.4.1
1111

1212
active-model:
1313
git: https://github.com/spider-gazelle/active-model.git
@@ -203,7 +203,7 @@ shards:
203203

204204
placeos-core:
205205
git: https://github.com/placeos/core.git
206-
version: 4.6.3+git.commit.552925ba4448e70bafeea10e008f10edc9a39f03
206+
version: 4.6.3+git.commit.4c0a8b37a3683435cdc51c891a81a2425b58a817
207207

208208
placeos-core-client:
209209
git: https://github.com/placeos/core-client.git

src/placeos-rest-api/controllers/application.cr

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -195,6 +195,13 @@ module PlaceOS::Api
195195
CommonError.new(error, false)
196196
end
197197

198+
# 408 if resource timed out
199+
@[AC::Route::Exception(IO::TimeoutError, status_code: HTTP::Status::REQUEST_TIMEOUT)]
200+
def resource_timeout(error) : CommonError
201+
Log.debug(exception: error) { error.message }
202+
CommonError.new(error, false)
203+
end
204+
198205
# when a client request fails validation
199206
@[AC::Route::Exception(JSON::ParseException, status_code: HTTP::Status::BAD_REQUEST)]
200207
@[AC::Route::Exception(JSON::SerializableError, status_code: HTTP::Status::BAD_REQUEST)]

src/placeos-rest-api/controllers/assets.cr

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -53,11 +53,12 @@ module PlaceOS::Api
5353
if include_instances
5454
# TODO:: we should make this part of the model (JSON write only lazy getter)
5555
# in the mean time this will work and our docs still look okay
56-
render json: with_fields(current_asset, {
56+
with_fields(current_asset, {
5757
"asset_instances" => current_asset.asset_instances.to_a,
5858
})
59+
else
60+
current_asset
5961
end
60-
current_asset
6162
end
6263

6364
@[AC::Route::PATCH("/:id", body: :asset)]

src/placeos-rest-api/controllers/cluster.cr

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -51,9 +51,9 @@ module PlaceOS::Api
5151
# [ { "uri": <uri>, "id": <id> }, ... ]
5252
details.map do |id, uri|
5353
{
54-
id: id,
55-
uri: uri,
56-
load: nil.as(PlaceOS::Core::Client::Load?),
54+
id: id,
55+
uri: uri,
56+
load: nil.as(PlaceOS::Core::Client::Load?),
5757
status: nil.as(PlaceOS::Core::Client::CoreStatus?),
5858
}.as(NodeStatus)
5959
end

src/placeos-rest-api/controllers/drivers.cr

Lines changed: 50 additions & 55 deletions
Original file line numberDiff line numberDiff line change
@@ -13,34 +13,26 @@ module PlaceOS::Api
1313
before_action :check_admin, except: [:index, :show]
1414
before_action :check_support, only: [:index, :show]
1515

16-
# Callbacks
1716
###############################################################################################
1817

19-
before_action :current_driver, only: [:show, :update, :update_alt, :destroy, :recompile]
20-
before_action :body, only: [:create, :update, :update_alt]
21-
22-
###############################################################################################
23-
24-
getter current_driver : Model::Driver do
25-
id = params["id"]
18+
@[AC::Route::Filter(:before_action, only: [:show, :update, :update_alt, :destroy, :recompile])]
19+
def current_driver(id : String)
2620
Log.context.set(driver_id: id)
2721
# Find will raise a 404 (not found) if there is an error
28-
Model::Driver.find!(id, runopts: {"read_mode" => "majority"})
22+
@current_driver = Model::Driver.find!(id, runopts: {"read_mode" => "majority"})
2923
end
3024

31-
###############################################################################################
25+
getter! current_driver : Model::Driver
3226

33-
def index
34-
# Pick off role from HTTP params, render error if present and invalid
35-
# TODO: This is an example of a need to improve validation model of params.
36-
role = params["role"]?.try &.to_i?.try do |r|
37-
parsed = Model::Driver::Role.from_value?(r)
38-
return render_error(HTTP::Status::UNPROCESSABLE_ENTITY, "Invalid `role`") if parsed.nil?
39-
parsed
40-
end
27+
###############################################################################################
4128

29+
@[AC::Route::GET("/")]
30+
def index(
31+
@[AC::Param::Info(description: "filter by the type of driver", example: "Logic")]
32+
role : Model::Driver::Role? = nil
33+
) : Array(Model::Driver)
4234
elastic = Model::Driver.elastic
43-
query = elastic.query(params)
35+
query = elastic.query(search_params)
4436

4537
if role
4638
query.filter({
@@ -50,51 +42,56 @@ module PlaceOS::Api
5042

5143
query.search_field "name"
5244
query.sort(NAME_SORT_ASC)
53-
render json: paginate_results(elastic, query)
45+
paginate_results(elastic, query)
5446
end
5547

56-
def show
57-
include_compilation_status = boolean_param("compilation_status", default: true)
58-
59-
result = !include_compilation_status ? current_driver : with_fields(current_driver, {
60-
:compilation_status => Api::Drivers.compilation_status(current_driver, request_id),
48+
@[AC::Route::GET("/:id")]
49+
def show(
50+
@[AC::Param::Info(name: "compilation_status", description: "check if the driver is compiled?", example: "false")]
51+
include_compilation_status : Bool = true
52+
) : Model::Driver | Hash(String, Hash(String, Bool) | JSON::Any)
53+
# TODO:: find an alternative for with_fields
54+
!include_compilation_status ? current_driver : with_fields(current_driver, {
55+
"compilation_status" => Api::Drivers.compilation_status(current_driver, request_id),
6156
})
62-
63-
render json: result
6457
end
6558

66-
def update
67-
current_driver.assign_attributes_from_json(self.body)
68-
69-
# Must destroy and re-add to change driver type
70-
return render_error(HTTP::Status::UNPROCESSABLE_ENTITY, "Driver role must not change") if current_driver.role_changed?
71-
72-
save_and_respond current_driver
59+
@[AC::Route::PATCH("/:id", body: :driver)]
60+
@[AC::Route::PUT("/:id", body: :driver)]
61+
def update(driver : Model::Driver) : Model::Driver
62+
current = current_driver
63+
current.assign_attributes(driver)
64+
raise Error::ModelValidation.new({ActiveModel::Error.new(current_driver, :role, "Driver role must not change")}) if current_driver.role_changed?
65+
raise Error::ModelValidation.new(current.errors) unless current.save
66+
current
7367
end
7468

75-
put_redirect
76-
77-
def create
78-
save_and_respond(Model::Driver.from_json(self.body))
69+
@[AC::Route::POST("/", body: :driver, status_code: HTTP::Status::CREATED)]
70+
def create(driver : Model::Driver) : Model::Driver
71+
raise Error::ModelValidation.new(driver.errors) unless driver.save
72+
driver
7973
end
8074

81-
def destroy
75+
@[AC::Route::DELETE("/:id", status_code: HTTP::Status::ACCEPTED)]
76+
def destroy : Nil
8277
current_driver.destroy
83-
head :ok
8478
end
8579

86-
post("/:id/recompile", :recompile) do
80+
@[AC::Route::POST("/:id/recompile", status: {
81+
Nil => HTTP::Status::ALREADY_REPORTED,
82+
})]
83+
def recompile : Model::Driver?
8784
if current_driver.commit.starts_with?("RECOMPILE")
88-
head :already_reported
85+
nil
8986
else
9087
if (recompiled = Drivers.recompile(current_driver))
9188
if recompiled.destroyed?
92-
head :not_found
89+
raise Error::NotFound.new("driver was deleted")
9390
else
94-
render json: recompiled
91+
recompiled
9592
end
9693
else
97-
head :request_timeout
94+
raise IO::TimeoutError.new("time exceeded waiting for driver to recompile")
9895
end
9996
end
10097
end
@@ -111,27 +108,25 @@ module PlaceOS::Api
111108
end
112109

113110
# Check if the core responsible for the driver has finished compilation
114-
#
115-
get("/:id/compiled", :compiled) do
111+
@[AC::Route::GET("/:id/compiled", status: {
112+
NamedTuple(compilation_output: String) => HTTP::Status::SERVICE_UNAVAILABLE,
113+
})]
114+
def compiled : Nil | NamedTuple(compilation_output: String)
116115
if (repository = current_driver.repository).nil?
117116
Log.error { {repository_id: current_driver.repository_id, message: "failed to load driver's repository"} }
118-
head :internal_server_error
117+
raise "failed to load driver's repository"
119118
end
120119

121120
compiled = self.class.driver_compiled?(current_driver, repository, request_id)
122-
123121
Log.info { "#{compiled ? "" : "not "}compiled" }
124122

125-
if compiled
126-
# Driver binary present
127-
head :ok
128-
else
123+
unless compiled
129124
if current_driver.compilation_output.nil?
130125
# Driver not compiled yet
131-
head :not_found
126+
raise Error::NotFound.new("Driver not compiled yet")
132127
else
133128
# Driver previously failed to compile
134-
render :service_unavailable, json: {compilation_output: current_driver.compilation_output}
129+
{compilation_output: current_driver.compilation_output.not_nil!}
135130
end
136131
end
137132
end

src/placeos-rest-api/error.cr

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -18,8 +18,8 @@ module PlaceOS::Api
1818
class ModelValidation < Error
1919
getter failures : Array(NamedTuple(field: Symbol, reason: String))
2020

21-
def initialize(failures : Array(ActiveModel::Error), message : String = "validation failed")
22-
@failures = failures.map { |fail| {field: fail.field, reason: fail.message} }
21+
def initialize(failures : Enumerable(ActiveModel::Error), message : String = "validation failed")
22+
@failures = failures.map { |fail| {field: fail.field, reason: fail.message} }.to_a
2323
super(message)
2424
end
2525
end

0 commit comments

Comments
 (0)