Skip to content

Commit

Permalink
Compile service: Support passing RHS kconfig and building RHS
Browse files Browse the repository at this point in the history
Specifying RHS kconfig will cause both firmware images to be built, which will
take twice as long as a LHS-only build. Clients should take care to only request
a RHS build for kconfig options that affect the peripheral behaviour.
  • Loading branch information
chrisandreae committed Oct 22, 2023
1 parent d35869d commit 8cfcfde
Show file tree
Hide file tree
Showing 8 changed files with 137 additions and 230 deletions.
4 changes: 2 additions & 2 deletions .github/workflows/build-container.yml
Original file line number Diff line number Diff line change
Expand Up @@ -60,11 +60,11 @@ jobs:
name: moergo-glove80-zmk-dev
authToken: "${{ secrets.CACHIX_AUTH_TOKEN }}"
- name: Build lambda image
run: nix-build release.nix --arg revision "\"${REVISION_TAG}\"" -A directLambdaImage -o directLambdaImage
run: nix-build release.nix --arg revision "\"${REVISION_TAG}\"" -A lambdaImage -o lambdaImage
- name: Import OCI image into docker-daemon
env:
REGISTRY: ${{ steps.login-ecr.outputs.registry }}
run: skopeo --insecure-policy copy oci:directLambdaImage docker-daemon:$REGISTRY/$ECR_REPOSITORY:$REVISION_TAG
run: skopeo --insecure-policy copy oci:lambdaImage docker-daemon:$REGISTRY/$ECR_REPOSITORY:$REVISION_TAG
- name: Push container image to Amazon ECR
env:
REGISTRY: ${{ steps.login-ecr.outputs.registry }}
Expand Down
4 changes: 0 additions & 4 deletions lambda/Gemfile
Original file line number Diff line number Diff line change
@@ -1,7 +1,3 @@
source 'https://rubygems.org'
gem 'aws_lambda_ric'
gem 'rack'
gem 'sinatra', '~> 2'

# The version on rubygems (1.0.7) is very out of date
gem 'serverless-rack', git: 'https://github.com/logandk/serverless-rack', branch: '7364305bc'
23 changes: 0 additions & 23 deletions lambda/Gemfile.lock
Original file line number Diff line number Diff line change
@@ -1,36 +1,13 @@
GIT
remote: https://github.com/logandk/serverless-rack
revision: 7364305bcbbf7f6cc6851497069a5a4cb91936b1
branch: 7364305bc
specs:
serverless-rack (1.0.7)
rack (~> 2.0)

GEM
remote: https://rubygems.org/
specs:
aws_lambda_ric (2.0.0)
mustermann (2.0.2)
ruby2_keywords (~> 0.0.1)
rack (2.2.4)
rack-protection (2.2.2)
rack
ruby2_keywords (0.0.5)
sinatra (2.2.2)
mustermann (~> 2.0)
rack (~> 2.2)
rack-protection (= 2.2.2)
tilt (~> 2.0)
tilt (2.0.11)

PLATFORMS
ruby

DEPENDENCIES
aws_lambda_ric
rack
serverless-rack!
sinatra (~> 2)

BUNDLED WITH
2.1.4
77 changes: 39 additions & 38 deletions lambda/app.rb
Original file line number Diff line number Diff line change
@@ -1,54 +1,42 @@
# frozen_string_literal: true

require 'rack'
require 'serverless_rack'

require './web_app'
require 'stringio'
require 'digest'
require 'json'
require './compiler'

$app = Rack::Builder.new do
run WebApp
end.to_app

module LambdaFunction
# Handle a API Gateway/ALB-structured HTTP request using the Sinatra app
class HttpHandler
def self.process(event:, context:)
handle_request(app: $app, event: event, context: context)
end
end

# Handle a non-HTTP proxied request, returning either the compiled result or
# an error as JSON.
class DirectHandler
# Handle a non-HTTP compile request, returning a JSON body of either the
# compiled result or an error.
class Handler
REVISION = ENV.fetch('REVISION', 'unknown')

def self.process(event:, context:)
return { type: 'keep_alive' } if event.has_key?('keep_alive')

keymap_data = event.fetch('keymap') do
return error(status: 400, message: 'Missing required argument: keymap')
parse_base64_param = ->(param, required: true) do
if event.include?(param)
Base64.strict_decode64(event.fetch(param))
elsif required
return error(status: 400, message: "Missing required argument: #{param}")
end
rescue ArgumentError
return error(status: 400, message: "Invalid Base64 in #{param} input")
end

keymap_data =
begin
Base64.strict_decode64(keymap_data)
rescue ArgumentError
return error(status: 400, message: 'Invalid Base64 in keymap input')
end
keymap_data = parse_base64_param.('keymap')
kconfig_data = parse_base64_param.('kconfig', required: false)

if event.has_key?('kconfig')
kconfig_data =
begin
Base64.strict_decode64(event['kconfig'])
rescue ArgumentError
return error(status: 400, message: 'Invalid Base64 in kconfig input')
end
end
# Including kconfig settings that affect the RHS require building both
# firmware images, doubling compile time. Clients should omit rhs_kconfig
# where possible.
rhs_kconfig_data = parse_base64_param.('rhs_kconfig', required: false)

result, log =
begin
Compiler.new.compile(keymap_data, kconfig_data)
log_compile(keymap_data, kconfig_data, rhs_kconfig_data)

Compiler.new.compile(keymap_data, kconfig_data, rhs_kconfig_data)
rescue Compiler::CompileError => e
return error(status: e.status, message: e.message, detail: e.log)
end
Expand All @@ -57,11 +45,24 @@ def self.process(event:, context:)

{ type: 'result', result: result, log: log, revision: REVISION }
rescue StandardError => e
error(status: 500, message: "Unexpected error: #{e.class}", detail: [e.message])
error(status: 500, message: "Unexpected error: #{e.class}", detail: [e.message], exception: e)
end

def self.error(status:, message:, detail: nil)
{ type: 'error', status: status, message: message, detail: detail, revision: REVISION }
def self.log_compile(keymap_data, kconfig_data, rhs_kconfig_data)
keymap = Digest::SHA1.base64digest(keymap_data)
kconfig = kconfig_data ? Digest::SHA1.base64digest(kconfig_data) : 'nil'
rhs_kconfig = rhs_kconfig_data ? Digest::SHA1.base64digest(rhs_kconfig_data) : 'nil'
puts("Compiling with keymap: #{keymap}; kconfig: #{kconfig}; rhs_kconfig: #{rhs_kconfig}")
end

def self.error(status:, message:, detail: nil, exception: nil)
reported_error = { type: 'error', status:, message:, detail:, revision: REVISION }

exception_detail = { class: exception.class, backtrace: exception.backtrace } if exception
logged_error = reported_error.merge(exception: exception_detail)
puts(JSON.dump(logged_error))

reported_error
end
end
end
35 changes: 28 additions & 7 deletions lambda/compiler.rb
Original file line number Diff line number Diff line change
Expand Up @@ -15,20 +15,41 @@ def initialize(message, status: 400, log:)
end
end

def compile(keymap_data, kconfig_data)
def compile(keymap_data, lhs_kconfig_data, rhs_kconfig_data)
if rhs_kconfig_data && !rhs_kconfig_data.empty?
lhs_result, lhs_output = compile_board('glove80_lh', keymap_data:, kconfig_data: lhs_kconfig_data, include_static_rhs: false)
rhs_result, rhs_output = compile_board('glove80_rh', keymap_data: nil, kconfig_data: rhs_kconfig_data, include_static_rhs: false)
[
lhs_result.concat(rhs_result),
["LHS Output:", *lhs_output, "RHS Output:", *rhs_output],
]
else
compile_board('glove80_lh', keymap_data:, kconfig_data: lhs_kconfig_data, include_static_rhs: true)
end
end

def compile_board(board, keymap_data:, kconfig_data:, include_static_rhs: false)
in_build_dir do
compile_command = ['compileZmk', './build.keymap']
compile_command = ['compileZmk', '-b', board]

File.open('build.keymap', 'w') { |io| io.write(keymap_data) }
if keymap_data
File.open('build.keymap', 'w') { |io| io.write(keymap_data) }
compile_command << '-k' << './build.keymap'
end

if kconfig_data
File.open('build.conf', 'w') { |io| io.write(kconfig_data) }
compile_command << './build.conf'
compile_command << '-c' << './build.conf'
end

if include_static_rhs
# Concatenate the pre-compiled glove80_rh image to the resulting uf2
compile_command << '-m'
end

compile_output = nil

IO.popen(compile_command, err: [:child, :out]) do |io|
IO.popen(compile_command, 'rb', err: [:child, :out]) do |io|
compile_output = io.read
end

Expand All @@ -39,11 +60,11 @@ def compile(keymap_data, kconfig_data)
raise CompileError.new("Compile failed with exit status #{status}", log: compile_output)
end

unless File.exist?('zephyr/combined.uf2')
unless File.exist?('zmk.uf2')
raise CompileError.new('Compile failed to produce result binary', status: 500, log: compile_output)
end

result = File.read('zephyr/combined.uf2')
result = File.read('zmk.uf2')

[result, compile_output]
end
Expand Down
76 changes: 0 additions & 76 deletions lambda/gemset.nix
Original file line number Diff line number Diff line change
Expand Up @@ -9,80 +9,4 @@
};
version = "2.0.0";
};
mustermann = {
dependencies = ["ruby2_keywords"];
groups = ["default"];
platforms = [];
source = {
remotes = ["https://rubygems.org"];
sha256 = "0m70qz27mlv2rhk4j1li6pw797gmiwwqg02vcgxcxr1rq2v53rnb";
type = "gem";
};
version = "2.0.2";
};
rack = {
groups = ["default"];
platforms = [];
source = {
remotes = ["https://rubygems.org"];
sha256 = "0axc6w0rs4yj0pksfll1hjgw1k6a5q0xi2lckh91knfb72v348pa";
type = "gem";
};
version = "2.2.4";
};
rack-protection = {
dependencies = ["rack"];
groups = ["default"];
platforms = [];
source = {
remotes = ["https://rubygems.org"];
sha256 = "169jzzgvbjrqmz4q55wp9pg4ji2h90mggcdxy152gv5vp96l2hgx";
type = "gem";
};
version = "2.2.2";
};
ruby2_keywords = {
groups = ["default"];
platforms = [];
source = {
remotes = ["https://rubygems.org"];
sha256 = "1vz322p8n39hz3b4a9gkmz9y7a5jaz41zrm2ywf31dvkqm03glgz";
type = "gem";
};
version = "0.0.5";
};
serverless-rack = {
dependencies = ["rack"];
groups = ["default"];
platforms = [];
source = {
fetchSubmodules = false;
rev = "7364305bcbbf7f6cc6851497069a5a4cb91936b1";
sha256 = "0c7ch0s0nl70p6ijg7q0jnq8ca2rhp5wqfp91kai81dy7d71mq65";
type = "git";
url = "https://github.com/logandk/serverless-rack";
};
version = "1.0.7";
};
sinatra = {
dependencies = ["mustermann" "rack" "rack-protection" "tilt"];
groups = ["default"];
platforms = [];
source = {
remotes = ["https://rubygems.org"];
sha256 = "0mbjp75dy35q796iard8izsy7gk55g2c3q864r2p13my3yjmlcvz";
type = "gem";
};
version = "2.2.2";
};
tilt = {
groups = ["default"];
platforms = [];
source = {
remotes = ["https://rubygems.org"];
sha256 = "186nfbcsk0l4l86gvng1fw6jq6p6s7rc0caxr23b3pnbfb20y63v";
type = "gem";
};
version = "2.0.11";
};
}
43 changes: 0 additions & 43 deletions lambda/web_app.rb

This file was deleted.

Loading

0 comments on commit 8cfcfde

Please sign in to comment.