Introduction to Turtle
Construct, Connect, & Scale code
Erica Windisch
Docker alumni and "Clouderati", 15 years experience in pioneering cloud architecture.
Apache 2.0 licensed
NodeJS module
CLI tool
Social coding
Embeddable in Go (others coming)
Turtle is...
Construct
Developers write CommonJS modules and combine them to create applications.
We can automatically combine user modules to create new and complex application workflows.
Connect
Just as a lambda is a blackbox,
so are APIs. Chain web services as you do functions.
Combined with code-building, your application can easily speak to any web service.
Scale
Because modules implementing functions are stateless and self-contained, they're easily dispatched to remote workers.
IOpipe simplifies the use of multi-threaded, parallelized, and distributed computing.
Code written for IOpipe can scale automatically.
Built for devs.
The goal of IOpipe is to make it easier to develop, integrate, and scale applications.
Integrate IOpipe into your application and immediately see the benefits of scale. As the number of users of IOpipe increase, more kernels will be available, simplifying development and integration efforts.
Built for sharing.
Share your code and allow others to construct new workflows with the pieces. IOpipe is the ultimate "DRY" tool which advocates small, reusable functions that can be shared and automatically recomposed by your team.
Built for IoT
The ability to connect to anything and effortlessly scale compute is an IoT unicorn.
IOpipe runs natively on the Tessel platform, and SBCs with Linux or Windows such as the RaspberryPI.
IOpipe is designed to be embeddable in languages such as C for running on a range of devices.
Kernels
- HTTP URLs (GET or POST)
- Native Functions
- CommonJS modules
module.exports = function(input, context) {
context.done(i)
}
module.exports.iopipe_typedef = {
"in": "*",
"out": "*"
}
Smallest "useful" kernel
# Import a kernel and name it com.example.SomeScript
$ iopipe import --name com.example.SomeScript - <<EOF
module.exports = function(_, context) {
context.done()
}
EOF
d9cb4fc46fd196806eab5906a5e125326ab59b1d096b189c485f298ef5093596
# List kernels
$ iopipe list
d9cb4fc46fd196806eab5906a5e125326ab59b1d096b189c485f298ef5093596
com.example.SomeScript
Management CLI
# Fetch response and process it with com.example.SomeScript
$ iopipe exec https://api.justyo.co/status/yoteam \
com.example.SomeScript
# Fetch response and convert it with SomeScript, sending the result to otherhost
$ iopipe exec https://api.justyo.co/status/yoteam \
com.example.SomeScript \
http://otherhost.example.com/request
# Fetch response and convert it with SomeScript, send that result to otherhost,
# & converting the response with the script ResponseScript
$ iopipe exec http://localhost/some-request com.example.SomeScript \
http://otherhost.example.com/request \
some.example.ResponseScript
# Export an NPM module:
$ iopipe export --name my-module-name \
http://localhost/some-request \
com.example.SomeScript
Management CLI
// Get number of commits by the top 100 contributors to iopipe
var iopipe = require("iopipe")
iopipe.exec("http://requestb.in/api/v1/bins"
,JSON.parse
,iopipe.property("name")
,
function(name) {
var rbin = "http://requestb.in/"+name
iopipe.exec(
"https://api.github.com/repos/iopipe/iopipe/stats/contributors"
,iopipe.callback(JSON.parse)
,iopipe.map(iopipe.property("total"))
,iopipe.reduce(function(x, y) { return x + y })
,rbin
)
console.log('<a href="' + rbin + '?inspect">View at requestb.in</a>')
})
NodeJS SDK
// Get number of commits by the top 100 contributors to iopipe
var iopipe = require("iopipe")
iopipe.exec("http://requestb.in/api/v1/bins"
,iopipe.callback(JSON.parse)
,iopipe.property("name")
,iopipe.define(
iopipe.tee(iopipe.define('<a href="'.concat
,iopipe.apply(
"concat"
,'?inspect">'+
'View at requestb.in</a>'))
,iopipe.define(
"https://api.github.com/repos/iopipe/" +
"iopipe/stats/contributors"
,iopipe.callback(JSON.parse)
,iopipe.map(iopipe.property("total"))
,iopipe.reduce(function(x, y) {
return x + y })
)
)
)
)
Functional syntax accepted
/* script1: Maps key-value pairs to an HTTP query string */
module.exports = function(input, context) {
var query = ""
for (var k in input) {
if (query === "") {
query += "?"
} else {
query += "&"
}
query = k + "=" + input[k]
}
context.done(query)
}
module.exports.iopipe_typedef = {
"in": "dictionary"
,"out": "HTTPQuery"
}
/* script2: Fetches hacker news top stories, filtered by a FirebaseQuery */
module.exports = function(input, context) {
var url = "https://hacker-news.firebaseio.com/v0/topstories.json"
iopipe.define(iopipe.callback(url.concat),
,iopipe.fetch, iopipe.callback(JSON.parse)
,context.done)(query)
}
module.exports.iopipe_typedef = {
"in": ["FirebaseQuery", "HTTPQuery"]
,"out": "[]HNitem.id"
}
HackerNews Top Stories
$ iopipe exec script1 script2 <<<'{ key: "value" }'
$ iopipe import --name searchHNUserNick <<EOF
module.exports = function(nick, context) {
iopipe.define("https://hacker-news.firebaseio.com/v0/item/".concat
,iopipe.callback(JSON.parse), iopipe.property("by")
,iopipe.tee(echo, "hasUserLinkedIn", "hasUserGitHub",context.done))
(nick)
}
function echo(i, cb) { cb(i) }
EOF
$ iopipe import --name hasUserLinkedIn <<EOF
module.exports = function(nick, context) {
try { iopipe.fetch("https://www.linkedin.com/in/".concat, function(_, c) { c.done(true) }
, context.done) } catch(e) { context.fail() }
}
EOF
$ iopipe import --name hasUserGitHub <<EOF
module.exports = function(nick, context) {
try { iopipe.fetch("https://www.github.com/".concat, function(_, c) { c.done(true) }
,context.done) } catch(e) { context.fail() }
}
EOF
$ iopipe import --name mapSearchUserHNTopstories <<EOF
module.exports = function(_, context) {
iopipe.exec("https://hacker-news.firebaseio.com/v0/topstories.json"
,iopipe.callback(JSON.parse)
,iopipe.map("searchHNUserNick"), context.done)
}
EOF
$ iopipe exec --dispatch=aws-lambda mapSearchUserHNTopstories
[ "ewindisch", true, true ]
...
Distributed compute
(work in progress)
https://hacker-news.firebaseio.com/v0/topstories.json
JSON.parse
map
searchHNUserNick
searchHNUserNick
searchHNUserNick
searchHNUserNick
"https://hacker-news.firebaseio.com/v0/item/".concat
iopipe.property("by")
tee
echo
hasUserLinkedIn
hasUserGithub
[ "someuser", true, false]
[ [ "someuser", true, false], ["user2", false, false], ["user3", true, true] ]
Distributed compute
Thank you
Questions?
erica@iopipe.com
@ewindisch
Join the IOpipe community at
https://github.com/iopipe/iopipe
Additional material
$ iopipe import --name getHNitemByID <<EOF
module.exports = function(HNitemID, context) {
iopipe.define("https://hacker-news.firebaseio.com/v0/item/".concat
,iopipe.callback(JSON.parse), context.done)(HNitemID)
}
EOF
$ iopipe import --name getHNitemUsername <<EOF
module.exports = function(HNitem, context) { context.done(HNitem.by) }
EOF
$ iopipe import --name searchUserByNick <<EOF
module.exports = function(nick, context) {
iopipe.tee(echo, "hasUserLinkedIn", "hasUserGitHub",context.done)
}
function echo(i, cb) { cb(i) }
EOF
$ iopipe import --name hasUserLinkedIn <<EOF
module.exports = function(nick, context) {
try { iopipe.fetch("https://www.linkedin.com/in/".concat, function(_, c) { c.done(true) }
, context.done) } catch(e) { context.fail() }
}
EOF
$ iopipe import --name hasUserGitHub <<EOF
module.exports = function(nick, context) {
try { iopipe.fetch("https://www.github.com/".concat, function(_, c) { c.done(true) }
,context.done) } catch(e) { context.fail() }
}
EOF
$ iopipe import --name mapSearchUserHNTopstories <<EOF
module.exports = function(_, context) {
iopipe.exec("https://hacker-news.firebaseio.com/v0/topstories.json"
,iopipe.callback(JSON.parse)
,iopipe.map("getHNitemByID", "getHNitemUsername", "searchUserByNick"), context.done)
}
EOF
$ iopipe exec --dispatch=aws-lambda mapSearchUserHNTopstories
[ "ewindisch", true, true ]
...
DRY distributed map
(work in progress)
Introduction to Turtle
By Erica Windisch
Introduction to Turtle
Writing code - with turtles all the way down
- 1,863