spellcheck
parent
1b6f43892c
commit
2c80868f99
|
@ -2,7 +2,7 @@ module Api
|
|||
# The API follows this workflow when creating a new image:
|
||||
# 1. Upload image to an S3 "untrusted" bucket (gets deleted quite often)
|
||||
# 2. POST the URL from step 1 (or any URL) to ImagesController#Create
|
||||
# 3. Image is transfered to the "trusted bucket".
|
||||
# 3. Image is transferred to the "trusted bucket".
|
||||
class ImagesController < Api::AbstractController
|
||||
cattr_accessor :store_locally
|
||||
self.store_locally = !ENV["GCS_BUCKET"]
|
||||
|
|
|
@ -36,7 +36,7 @@ module Api
|
|||
|
||||
def trim_logs
|
||||
# WARNING: Calls to `destroy_all` rather than
|
||||
# `delete_all` can be disasterous- this is
|
||||
# `delete_all` can be disastrous- this is
|
||||
# a big table! RC
|
||||
current_device.excess_logs.delete_all
|
||||
end
|
||||
|
|
|
@ -6,7 +6,7 @@ module Api
|
|||
|
||||
CREDS = Auth::CreateTokenFromCredentials
|
||||
NO_CREDS = Auth::CreateToken
|
||||
NO_USER_ATTR = "API requets need a `user` attribute that is a JSON object."
|
||||
NO_USER_ATTR = "API requests need a `user` attribute that is a JSON object."
|
||||
|
||||
# Give you the same token, but reloads all claims except `exp`
|
||||
def show
|
||||
|
|
|
@ -45,7 +45,7 @@ class AmqpLogParser < Mutations::Command
|
|||
!problems.present?
|
||||
end
|
||||
|
||||
# Prevents "runaway" bots from flooding the server with frivoulous database
|
||||
# Prevents "runaway" bots from flooding the server with frivolous database
|
||||
# hits by using in memory cache of results for 150 seconds.
|
||||
def device
|
||||
Device.cached_find(device_id)
|
||||
|
@ -89,7 +89,7 @@ private
|
|||
(log["major_version"] || log.dig("meta", "major_version") || 0).to_i
|
||||
end
|
||||
|
||||
# Weed out anamolies such as logs that are array types.
|
||||
# Weed out anomalies such as logs that are array types.
|
||||
def not_hash?
|
||||
!log.is_a?(Hash)
|
||||
end
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
# Base calss for every "thing" that is found in a CeleryScript AST.
|
||||
# Base class for every "thing" that is found in a CeleryScript AST.
|
||||
module CeleryScript
|
||||
# Abstract class that AstLeaf and AstNode inherit from.
|
||||
# Use this for shared leaf/node behavior.
|
||||
|
|
|
@ -16,7 +16,7 @@ module CeleryScript
|
|||
# Certain CeleryScript pairing errors are more than just a syntax error.
|
||||
# For instance, A `nothing` node in a `parameter_declaration` is often an
|
||||
# indication that the user did not fill out a value for a variable. In these
|
||||
# rare cases, we muct provide information beyond what is found in the
|
||||
# rare cases, we must provide information beyond what is found in the
|
||||
# BAD_LEAF template.
|
||||
FRIENDLY_ERRORS = {
|
||||
nothing: {
|
||||
|
@ -182,7 +182,7 @@ module CeleryScript
|
|||
corpus.arg_validator(expectation).call(node, device)
|
||||
end
|
||||
|
||||
# Calling this method with only one paramter
|
||||
# Calling this method with only one parameter
|
||||
# indicates a starting condition 🏁
|
||||
def resolve_variable!(node, origin = node)
|
||||
locals = node.args[:locals]
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
# Re-combingind EdgeNodes and PrimaryNodes is very query intensive.
|
||||
# Re-combining EdgeNodes and PrimaryNodes is very query intensive.
|
||||
# To avoid excess DB calls, we will index the nodes in memory by field type.
|
||||
module CeleryScript
|
||||
# EXAMPLE USAGE:
|
||||
|
@ -33,4 +33,4 @@
|
|||
@by = struct
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
require_relative "./csheap.rb"
|
||||
# ORIGINAL IMPLEMENTATION HERE: https://github.com/FarmBot-Labs/Celery-Slicer
|
||||
# Take a nested ("canonical") representation of a CeleryScript sequence and
|
||||
# transofrms it to a flat/homogenous intermediate representation which is better
|
||||
# transforms it to a flat/homogenous intermediate representation which is better
|
||||
# suited for storage in a relational database.
|
||||
module CeleryScript
|
||||
class Slicer
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
# Creates asymetric key pairs for cryptographically secure operations.
|
||||
# Creates asymmetric key pairs for cryptographically secure operations.
|
||||
# Mostly used for creation of jwt.pem- which is used to verify authenticity of
|
||||
# JSON Web Tokens
|
||||
class KeyGen
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
# A singleton that runs on a seperate process than the web server.
|
||||
# A singleton that runs on a separate process than the web server.
|
||||
# Listens to *ALL* incoming logs and stores them to the DB.
|
||||
# Also handles throttling.
|
||||
class LogService
|
||||
|
|
|
@ -35,7 +35,7 @@ class NervesHub
|
|||
# * FarmBot makes an authenticated call to the FarmBot API asking for a
|
||||
# NervesHub SSL Private Key/Cert combo.
|
||||
# * FarmBot API makes a call to NervesHub generating a `device` resource.
|
||||
# * FarmBot API makes a call to NervesHub generating a `device_cert` resouce.
|
||||
# * FarmBot API makes a call to NervesHub generating a `device_cert` resource.
|
||||
# * This require creating a CSR (certificate signing request).
|
||||
# * FarmBot API sends this cert (without saving it) directly to the FarmBot
|
||||
# via AMQP.
|
||||
|
@ -82,7 +82,7 @@ class NervesHub
|
|||
update(serial_number, next_tags)
|
||||
end
|
||||
|
||||
# Checks if a deivce exists in NervesHub
|
||||
# Checks if a device exists in NervesHub
|
||||
# if it does -> does a PUT request updating the tags.
|
||||
# if it does not -> does a POST request creating the device with given tags.
|
||||
def self.create_or_update(serial_number, tags)
|
||||
|
@ -271,7 +271,7 @@ private
|
|||
|
||||
# This is a hack because Ruby "net/http" client doesn't
|
||||
# Allow loading this as a normal cert, it only allows
|
||||
# loading a flie from the filesystem.
|
||||
# loading a file from the filesystem.
|
||||
# https://stackoverflow.com/questions/36993208/how-to-enumerate-through-multiple-certificates-in-a-bundle
|
||||
def self.try_env_ca_file
|
||||
if ENV['NERVES_HUB_CA']
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
module Resources
|
||||
DEVICE_REGEX = /device_\d*/
|
||||
ACTIONS = [ DESTROY = "destroy", SAVE = "save" ]
|
||||
# Resources eligibile for the MQTT-based APIs
|
||||
# Resources eligible for the MQTT-based APIs
|
||||
ELIGIBLE_RESOURCES = [ FarmEvent,
|
||||
FarmwareInstallation,
|
||||
Image,
|
||||
|
@ -41,8 +41,8 @@ module Resources
|
|||
Tool => Tools,
|
||||
WebcamFeed => WebcamFeeds,
|
||||
# SPECIAL CASES =============================
|
||||
# These reasources don't follow usual
|
||||
# naming coonventions.
|
||||
# These resources don't follow usual
|
||||
# naming conventions.
|
||||
Plant => Points,
|
||||
Point => Points,
|
||||
ToolSlot => Points,
|
||||
|
|
|
@ -3,7 +3,7 @@ module Resources
|
|||
# into fully formed
|
||||
class Preprocessor < Mutations::Command
|
||||
def self.from_amqp(delivery_info, body)
|
||||
# Parse the AMQP rotuing key into an Array of strings.
|
||||
# Parse the AMQP routing key into an Array of strings.
|
||||
# A properly formatted routing_key will look like this after processing:
|
||||
#
|
||||
# ["bot", "device_3", "resources_v0", "destroy", "Sequence", "2", "xyz"]
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
# SCENARIO: RabbitMQ's HTTP auth backend plugin uses *files* instead of ENV vars
|
||||
# for configuration.
|
||||
# PROBLEM: 1. This is the only service that requires such configuartion. All
|
||||
# PROBLEM: 1. This is the only service that requires such configuration. All
|
||||
# other services are configured in one place- the `.env` file.
|
||||
# 2. When using files, it's easy to forget that the file needs updates.
|
||||
# Refreshing the .env file will NOT refresh rabbit configs.
|
||||
|
|
|
@ -1,11 +1,11 @@
|
|||
# Handles devices that spin out of control and send too many logs to the server.
|
||||
# Class Hierarchy:
|
||||
# ThrotllePolicy has => Rules creates => Violation
|
||||
# ThrottlePolicy has => Rules creates => Violation
|
||||
# Violation has => Rule has => TimePeriod
|
||||
class ThrottlePolicy
|
||||
attr_reader :rules
|
||||
|
||||
# Dictionary<TimePeriod, Intger>
|
||||
# Dictionary<TimePeriod, Integer>
|
||||
def initialize(policy_rules)
|
||||
@rules = policy_rules.map { |rule_set| Rule.new(*rule_set) }
|
||||
end
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
# Track the number of occurences of an event over time.
|
||||
# Track the number of occurrences of an event over time.
|
||||
#
|
||||
# Given:
|
||||
# * A fixed size duration (1 minute, 1 week etc)
|
||||
|
|
|
@ -15,7 +15,7 @@ module CeleryScriptSettingsBag
|
|||
end
|
||||
end
|
||||
|
||||
# List of all celery script nodes that can be used as a varaible...
|
||||
# List of all celery script nodes that can be used as a variable...
|
||||
ANY_VARIABLE = %i(tool coordinate point identifier every_point)
|
||||
PLANT_STAGES = %w(planned planted harvested sprouted)
|
||||
ALLOWED_PIN_MODES = [DIGITAL = 0, ANALOG = 1]
|
||||
|
@ -85,7 +85,7 @@ module CeleryScriptSettingsBag
|
|||
.arg(:_then, [:execute, :nothing])
|
||||
.arg(:locals, [:scope_declaration])
|
||||
.arg(:offset, [:coordinate])
|
||||
.arg(:pin_number, [Integer, :named_pin]) # HETEROGENUS ARG TYPE => BAD
|
||||
.arg(:pin_number, [Integer, :named_pin]) # HETEROGENEOUS ARG TYPE => BAD
|
||||
.arg(:data_value, ANY_VARIABLE)
|
||||
.arg(:default_value,ANY_VARIABLE)
|
||||
.arg(:location, ANY_VARIABLE)
|
||||
|
@ -246,8 +246,8 @@ module CeleryScriptSettingsBag
|
|||
.node(:remove_farmware, [:package])
|
||||
.node(:scope_declaration, [], SCOPE_DECLARATIONS)
|
||||
.node(:identifier, [:label])
|
||||
.node(:variable_declaration, [:label, :data_value], []) # duplicate nodes evolve independendantly
|
||||
.node(:parameter_application, [:label, :data_value], []) # duplicate nodes evolve independendantly
|
||||
.node(:variable_declaration, [:label, :data_value], []) # duplicate nodes evolve independently
|
||||
.node(:parameter_application, [:label, :data_value], []) # duplicate nodes evolve independently
|
||||
.node(:parameter_declaration, [:label, :default_value], [])
|
||||
.node(:set_servo_angle, [:pin_number, :pin_value], [])
|
||||
.node(:change_ownership, [], [:pair])
|
||||
|
@ -275,7 +275,7 @@ module CeleryScriptSettingsBag
|
|||
when "Device"
|
||||
# When "resource_type" is "Device", resource_id always refers to
|
||||
# the current_device.
|
||||
# For convinience, we try to set it here, defaulting to 0
|
||||
# For convenience, we try to set it here, defaulting to 0
|
||||
node.args[:resource_id].instance_variable_set("@value", 0)
|
||||
when *RESOURCE_NAME.without("Device")
|
||||
klass = Kernel.const_get(resource_type)
|
||||
|
|
|
@ -69,7 +69,7 @@ class Device < ApplicationRecord
|
|||
end
|
||||
|
||||
# Sets Device.current to `self` and returns it to the previous value when
|
||||
# finished running block. Usually this is unecessary, but may be required in
|
||||
# finished running block. Usually this is unnecessary, but may be required in
|
||||
# background jobs. If you are not receiving auto_sync data on your client,
|
||||
# you probably need to use this method.
|
||||
def auto_sync_transaction
|
||||
|
@ -164,7 +164,7 @@ class Device < ApplicationRecord
|
|||
# * We converted the `model :device, class: Device` to:
|
||||
# `duck :device, methods [:id, :is_device]`
|
||||
#
|
||||
# This methd is not required, but adds a layer of safety.
|
||||
# This method is not required, but adds a layer of safety.
|
||||
def is_device # SEE: Hack in Log::Create. TODO: Fix low level caching bug.
|
||||
true
|
||||
end
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
# SCHEDULED DEPRECATION:
|
||||
# Node/PrimaryPair/PrimitivePair/Fragment will superceeded this model
|
||||
# Node/PrimaryPair/PrimitivePair/Fragment will supersede this model
|
||||
# eventually
|
||||
# In a CeleryScript flat IR tree, primitive values are stored as edge nodes.
|
||||
# Canonical representation:
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
# Not the same thing as a Regimen. A farm_event is a "dumb" list of sequecnes that
|
||||
# Not the same thing as a Regimen. A farm_event is a "dumb" list of sequences that
|
||||
# are executed at fixed intervals. FarmEvents are less flexible than Regimens
|
||||
# because they can only perform one sequence. Also unlike Regimens, they can run
|
||||
# forever.
|
||||
|
|
|
@ -18,7 +18,7 @@ class FarmwareInstallation < ApplicationRecord
|
|||
SocketError =>
|
||||
"The server at the provided appears to be offline.",
|
||||
Net::OpenTimeout =>
|
||||
"A timeout error occured.",
|
||||
"A timeout error occurred.",
|
||||
JSON::ParserError =>
|
||||
"Expected Farmware manifest to be valid JSON, "\
|
||||
"but it is not. Consider using a JSON validator.",
|
||||
|
|
|
@ -16,7 +16,7 @@ class FbosConfig < ApplicationRecord
|
|||
unless serial
|
||||
# This feature can be removed in May '19
|
||||
# It is used to repair data damage on
|
||||
# production during the initial nervehub
|
||||
# production during the initial nerveshub
|
||||
# deployment.
|
||||
problem = "Device #{device.id} missing serial"
|
||||
NervesHub.report_problem({ problem: problem })
|
||||
|
|
|
@ -1,12 +1,12 @@
|
|||
# The most complicated part of the application. The text below describes the
|
||||
# implemntation details for CeleryScript, a visual programming langue and RPC
|
||||
# implementation details for CeleryScript, a visual programming language and RPC
|
||||
# format. READ FIRST: https://developer.farm.bot/docs/celery-script
|
||||
#
|
||||
# PROBLEM: You need to store a CeleryScript AST in a way that is:
|
||||
#
|
||||
# * REUSABLE - Can be used on any resource that is scriptable (Sequence,
|
||||
# FarmEvent, Regimen, etc...)
|
||||
# * Normalized - Has a flat strucutre that is advantageous to SQL storage, can
|
||||
# * Normalized - Has a flat structure that is advantageous to SQL storage, can
|
||||
# easily perform operations such as global renaming .
|
||||
# * Searchable - Able to answer questions like "Are any Celery nodes
|
||||
# referencing sequence 123?" or "How many FarmEvents have 3
|
||||
|
@ -35,12 +35,12 @@
|
|||
# [ArgSet]
|
||||
# ^
|
||||
# |\
|
||||
# | `----[PrimtivePair]-> (Primitive, ArgName pairing)
|
||||
# | `----[PrimitivePair]-> (Primitive, ArgName pairing)
|
||||
# |
|
||||
# [StandardPair]--> (Node, ArgName pairing)
|
||||
#
|
||||
# HOW STORAGE WORKS (Fragments::Create):
|
||||
# 1. Canonical CelryScript is sliced into a flat IR
|
||||
# 1. Canonical CeleryScript is sliced into a flat IR
|
||||
# 2. Flat IR is further decomposed into Node, ArgSet, ArgName,
|
||||
# StandardPair, PrimitivePair.
|
||||
#
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
# Used by third party farmwares (eg: weed-detection) to mark points on a map.
|
||||
# Used by third party Farmware (eg: weed-detection) to mark points on a map.
|
||||
class GenericPointer < Point
|
||||
def name_used_when_syncing
|
||||
"Point"
|
||||
|
|
|
@ -29,7 +29,7 @@ class GlobalConfig < ApplicationRecord
|
|||
end
|
||||
|
||||
# Memoized version of every GlobalConfig, with key/values layed out in a hash.
|
||||
# Database values prempt values set in ::DEFAULTS
|
||||
# Database values preempt values set in ::DEFAULTS
|
||||
def self.dump
|
||||
@dump ||= reload_
|
||||
end
|
||||
|
|
|
@ -51,7 +51,7 @@ class Image < ApplicationRecord
|
|||
# User clicks "take photo" and "delete" on Image#123 very quickly.
|
||||
# Problem:
|
||||
# Now there's a Delayed::Job pointing to (nonexistent) Image#123,
|
||||
# causing runtime errrors in the work queue.
|
||||
# causing runtime errors in the work queue.
|
||||
# Solution:
|
||||
# Don't retry failed deletions. Users can always click the "delete"
|
||||
# button again if need be.
|
||||
|
|
|
@ -3,9 +3,9 @@
|
|||
class Log < ApplicationRecord
|
||||
include LogDeliveryStuff
|
||||
# We use log.type to store the log's type.
|
||||
# Rails wants to use that name for single table inheritence, which we don't
|
||||
# Rails wants to use that name for single table inheritance, which we don't
|
||||
# need for this table.
|
||||
# Setting the `inheritence_column` to "none" alleviate
|
||||
# Setting the `inheritance_column` to "none" alleviate
|
||||
self.inheritance_column = "none"
|
||||
# Used by the frontend to pull most recent records. We don't currently support
|
||||
# pagination, but could later on.
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
# SCHEDULED DEPRECATION:
|
||||
# Node/PrimaryPair/PrimitivePair/Fragment will superceeded this model
|
||||
# Node/PrimaryPair/PrimitivePair/Fragment will supersede this model
|
||||
# eventually
|
||||
# If a node in the sequence node tree has a `kind` and `args` property, it is
|
||||
# said to be a properly formed "PrimaryNode". Everything else is an `EdgeNode`.
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
# Various convinience features and flags.
|
||||
# Various convenience features and flags.
|
||||
class WebAppConfig < ApplicationRecord
|
||||
belongs_to :device
|
||||
|
||||
|
|
|
@ -15,10 +15,10 @@ module Auth
|
|||
end
|
||||
|
||||
def execute
|
||||
security_criticial_danger = claims["exp"] # Stop infinite sessions
|
||||
security_critical_danger = claims["exp"] # Stop infinite sessions
|
||||
token = SessionToken.issue_to(user,
|
||||
aud: claims["aud"],
|
||||
exp: security_criticial_danger,
|
||||
exp: security_critical_danger,
|
||||
fbos_version: fbos_version)
|
||||
return { token: token }
|
||||
end
|
||||
|
|
|
@ -118,7 +118,7 @@ module FarmBot
|
|||
upgrade_insecure_requests: false, # WHY? Some people run webcam feeds
|
||||
# over plain http://. I wish they
|
||||
# wouldn't, but I think it's too much
|
||||
# of an inconvinience to block that
|
||||
# of an inconvenience to block that
|
||||
# feature. Comments welcome -RC.
|
||||
report_uri: %w(/csp_reports)
|
||||
}
|
||||
|
|
|
@ -43,7 +43,7 @@ FarmBot::Application.routes.draw do
|
|||
|
||||
resources :logs, except: [:update, :show] do
|
||||
# When farmware fetching fails and the user
|
||||
# wants to try agian.
|
||||
# wants to try again.
|
||||
get :search, on: :collection
|
||||
end
|
||||
|
||||
|
|
|
@ -41,7 +41,7 @@ describe Api::FbosConfigsController do
|
|||
end
|
||||
|
||||
describe '#update' do
|
||||
it 'raise integer overflow erorrs' do
|
||||
it 'raise integer overflow errors' do
|
||||
way_too_big = 123456789013333333332345
|
||||
sign_in user
|
||||
body = { network_not_found_timer: way_too_big }
|
||||
|
|
|
@ -34,7 +34,7 @@ describe Api::PasswordResetsController do
|
|||
expect(json.keys).to include(:user)
|
||||
end
|
||||
|
||||
it 'dissallows short passwords' do
|
||||
it 'disallows short passwords' do
|
||||
params = {password: "xpass",
|
||||
password_confirmation: "xpass",
|
||||
fbos_version: Gem::Version.new("999.9.9"),
|
||||
|
|
|
@ -29,7 +29,7 @@ describe Api::SequencesController do
|
|||
expect(response.status).to eq(404)
|
||||
end
|
||||
|
||||
it 'allows deletion of recurive sequences' do
|
||||
it 'allows deletion of recursive sequences' do
|
||||
sign_in user
|
||||
s = Sequences::Create.run!({device: user.device,
|
||||
name: "Rick-cursion",
|
||||
|
|
|
@ -76,11 +76,11 @@ DatabaseCleaner.clean
|
|||
|
||||
RSpec.configure do |config|
|
||||
if DO_INTEGRATION
|
||||
# Do I need to run `env RAILS_ENV=productiono npm run build`?
|
||||
# Do I need to run `env RAILS_ENV=production npm run build`?
|
||||
require "capybara/rails"
|
||||
require "capybara/rspec"
|
||||
require "selenium/webdriver"
|
||||
# Be sure to run the server in a seperate window!
|
||||
# Be sure to run the server in a separate window!
|
||||
Capybara.run_server = false
|
||||
Capybara.app_host = "http://localhost:3000"
|
||||
Capybara.server_host = "localhost"
|
||||
|
|
Loading…
Reference in New Issue