Skip to content

Commit

Permalink
feat: add Rust functions runtime (#3037)
Browse files Browse the repository at this point in the history
  • Loading branch information
eduardoboucas authored Jul 30, 2021
1 parent 9f8d7a4 commit 9248675
Show file tree
Hide file tree
Showing 7 changed files with 205 additions and 115 deletions.
210 changes: 105 additions & 105 deletions npm-shrinkwrap.json

Large diffs are not rendered by default.

4 changes: 2 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -79,7 +79,7 @@
"@netlify/build": "^17.3.1",
"@netlify/config": "^14.1.0",
"@netlify/framework-info": "^5.7.2",
"@netlify/local-functions-proxy": "^1.0.0",
"@netlify/local-functions-proxy": "^1.1.0",
"@netlify/plugin-edge-handlers": "^1.11.22",
"@netlify/plugins-list": "^2.21.0",
"@netlify/routing-local-proxy": "^0.31.0",
Expand Down Expand Up @@ -181,6 +181,7 @@
"through2-filter": "^3.0.0",
"through2-map": "^3.0.0",
"to-readable-stream": "^2.1.0",
"toml": "^3.0.0",
"update-notifier": "^5.0.0",
"uuid": "^8.0.0",
"wait-port": "^0.2.2",
Expand Down Expand Up @@ -211,7 +212,6 @@
"sort-on": "^4.1.0",
"strip-ansi": "^6.0.0",
"temp-dir": "^2.0.0",
"toml": "^3.0.0",
"tomlify-j0.4": "^3.0.0",
"tree-kill": "^1.2.2"
},
Expand Down
15 changes: 14 additions & 1 deletion src/lib/functions/local-proxy.js
Original file line number Diff line number Diff line change
@@ -1,8 +1,21 @@
const { getBinaryPath: getFunctionsProxyPath } = require('@netlify/local-functions-proxy')
const execa = require('execa')

const runFunctionsProxy = ({ binaryPath, directory, name, requestData, timeout }) => {
const runFunctionsProxy = ({ binaryPath, context, directory, event, name, timeout }) => {
const functionsProxyPath = getFunctionsProxyPath()
const requestData = {
resource: '',
...event,
headers: {
...event.headers,
'X-Amzn-Trace-Id': '1a2b3c4d5e6f',
},
requestContext: {
...context,
httpMethod: event.httpMethod || 'GET',
requestTimeEpoch: 0,
},
}

if (functionsProxyPath === null) {
throw new Error('Host machine does not support local functions proxy server')
Expand Down
5 changes: 4 additions & 1 deletion src/lib/functions/registry.js
Original file line number Diff line number Diff line change
Expand Up @@ -152,7 +152,10 @@ class FunctionsRegistry {
await Promise.all(directories.map((path) => FunctionsRegistry.prepareDirectoryScan(path)))

const functions = await this.listFunctions(directories, {
featureFlags: { buildGoSource: env.NETLIFY_EXPERIMENTAL_BUILD_GO_SOURCE === 'true' },
featureFlags: {
buildGoSource: env.NETLIFY_EXPERIMENTAL_BUILD_GO_SOURCE === 'true',
buildRustSource: env.NETLIFY_EXPERIMENTAL_BUILD_RUST_SOURCE === 'true',
},
})

// Before registering any functions, we look for any functions that were on
Expand Down
7 changes: 2 additions & 5 deletions src/lib/functions/runtimes/go/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -44,15 +44,12 @@ const getBuildFunction = ({ func }) => {
}

const invokeFunction = async ({ context, event, func, timeout }) => {
const requestData = {
...event,
requestContext: context,
}
const { stdout } = await runFunctionsProxy({
binaryPath: func.buildData.binaryPath,
context,
directory: dirname(func.mainFile),
event,
name: func.name,
requestData,
timeout,
})

Expand Down
3 changes: 2 additions & 1 deletion src/lib/functions/runtimes/index.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
const go = require('./go')
const js = require('./js')
const rust = require('./rust')

/**
* @callback BuildFunction
Expand Down Expand Up @@ -40,6 +41,6 @@ const js = require('./js')
* @property {string} name
*/

const runtimes = [js, go].reduce((res, runtime) => ({ ...res, [runtime.name]: runtime }), {})
const runtimes = [js, go, rust].reduce((res, runtime) => ({ ...res, [runtime.name]: runtime }), {})

module.exports = runtimes
76 changes: 76 additions & 0 deletions src/lib/functions/runtimes/rust/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
const { dirname, extname, join, resolve } = require('path')
const { platform } = require('process')

const execa = require('execa')
const findUp = require('find-up')
const toml = require('toml')

const isWindows = platform === 'win32'

const { readFileAsync } = require('../../../fs')
const { getPathInProject } = require('../../../settings')
const { runFunctionsProxy } = require('../../local-proxy')

const build = async ({ func }) => {
const functionDirectory = dirname(func.mainFile)
const cacheDirectory = resolve(getPathInProject(['functions-serve']))
const targetDirectory = join(cacheDirectory, func.name)
const crateName = await getCrateName(functionDirectory)
const binaryName = `${crateName}${isWindows ? '.exe' : ''}`
const binaryPath = join(targetDirectory, 'debug', binaryName)

await execa('cargo', ['build', '--target-dir', targetDirectory], {
cwd: functionDirectory,
})

return {
binaryPath,
srcFiles: [functionDirectory],
}
}

const getBuildFunction =
({ func }) =>
() =>
build({ func })

const getCrateName = async (cwd) => {
const manifestPath = await findUp('Cargo.toml', { cwd, type: 'file' })
const manifest = await readFileAsync(manifestPath)
const { package } = toml.parse(manifest)

return package.name
}

const invokeFunction = async ({ context, event, func, timeout }) => {
const { stdout } = await runFunctionsProxy({
binaryPath: func.buildData.binaryPath,
context,
directory: dirname(func.mainFile),
event,
name: func.name,
timeout,
})

try {
const { body, headers, statusCode } = JSON.parse(stdout)

return {
body,
headers,
statusCode,
}
} catch (error) {
return {
statusCode: 500,
}
}
}

const onRegister = (func) => {
const isSource = extname(func.mainFile) === '.rs'

return isSource ? func : null
}

module.exports = { getBuildFunction, invokeFunction, name: 'rs', onRegister }

1 comment on commit 9248675

@github-actions
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

📊 Benchmark results

Package size: 331 MB

Please sign in to comment.