Skip to content

Instantly share code, notes, and snippets.

@billywhizz
Last active August 22, 2022 01:06
Show Gist options
  • Save billywhizz/8d05970be14291537fcb4aa3ca385a42 to your computer and use it in GitHub Desktop.
Save billywhizz/8d05970be14291537fcb4aa3ca385a42 to your computer and use it in GitHub Desktop.
just http baseline

Download and build just-js and required libraries and run the server

curl -L -o just.tar.gz https://github.com/just-js/just/archive/current.tar.gz
mkdir -p just && tar -zxvf just.tar.gz -C just --strip-components 1
make -C just runtime
sudo make -C just install install-debug
export JUST_HOME=$(pwd)/just
export JUST_TARGET=$JUST_HOME
make -C just/modules/http library
make -C just/modules/sha1 library
# these will install libraries to /usr/local/lib, where runtime looks for them
# yes, i should change this and tie it to JUST_HOME
sudo make -C just/modules/http install install-debug 
sudo make -C just/modules/sha1 install install-debug
make -C just libs
CPUS=1 just http.js
const { epoll } = just.load('epoll')
const { sys } = just.load('sys')
const { net } = just.load('net')
const { http } = just.library('http')
const spawn = require('spawn.js')
const {
close, recv, send, accept4, setsockopt, socket, bind, listen, SOMAXCONN
} = net
const {
O_NONBLOCK, AF_INET, SOCK_STREAM, SOL_SOCKET, SO_REUSEADDR, SO_REUSEPORT,
SOCK_NONBLOCK
} = net
const {
create, wait, control, EPOLL_CLOEXEC, EPOLL_CTL_ADD, EPOLL_CTL_MOD, EPOLLIN,
EPOLLERR, EPOLLHUP
} = epoll
const {
parseRequestsHandle, createHandle
} = http
function add (fd, callback, events = EPOLLIN) {
const r = control(loopfd, EPOLL_CTL_ADD, fd, events)
if (r === 0) handles[fd] = callback
return r
}
function update (fd, events = EPOLLIN) {
return control(loopfd, EPOLL_CTL_MOD, fd, events)
}
function poll (timeout = -1, sigmask) {
let r = 0
if (sigmask) {
r = wait(loopfd, evbuf, timeout, sigmask)
} else {
r = wait(loopfd, evbuf, timeout)
}
if (r > 0) {
let off = 0
for (let i = 0; i < r; i++) {
const fd = events[off + 1]
handles[fd] && handles[fd](fd, events[off])
off += 3
}
}
return r
}
function onSocketEvent (fd, event) {
if (event & EPOLLERR || event & EPOLLHUP) {
close(fd)
return
}
const bytes = recv(fd, buf, 0, bufferSize)
if (bytes > 0) {
parseRequestsHandle(handle, bytes, 0)
const [count] = u16
if (count > 1) {
if (count > maxPipeline) {
send(fd, r400, count * r400Len, 0)
close(fd)
return
}
send(fd, r200, count * r200Len, 0)
return
}
send(fd, r200, r200Len, 0)
return
}
if (bytes < 0) just.error('recv error')
close(fd)
}
function onConnect (fd, event) {
if (event & EPOLLERR || event & EPOLLHUP) {
close(fd)
return
}
const newfd = accept4(fd, O_NONBLOCK)
add(newfd, onSocketEvent)
update(newfd, EPOLLIN | EPOLLERR | EPOLLHUP)
}
const handles = {}
const bufferSize = 16384
const r200 = sys.calloc(1, `HTTP/1.1 200 OK\r\nServer: j\r\nContent-Type: text/plain\r\nDate: ${(new Date()).toUTCString()}\r\nContent-Length: 11\r\n\r\nHello World`)
const r400 = sys.calloc(1, `HTTP/1.1 400 Bad Request\r\nServer: j\r\nContent-Type: text/plain\r\n\r\nDate: ${(new Date()).toUTCString()}\r\nContent-Length: 0\r\nConnection: close\r\n\r\n`)
const r200Len = r200.byteLength
const r400Len = r400.byteLength
const buf = new ArrayBuffer(bufferSize)
const info = new ArrayBuffer(4)
const u16 = new Uint16Array(info)
const handle = createHandle(buf, info)
const nevents = 1024
const evbuf = new ArrayBuffer(nevents * 12)
const events = new Uint32Array(evbuf)
let fd
let loopfd
function main () {
fd = socket(AF_INET, SOCK_STREAM | SOCK_NONBLOCK, 0)
setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, 1)
setsockopt(fd, SOL_SOCKET, SO_REUSEPORT, 1)
bind(fd, '127.0.0.1', 3000)
listen(fd, SOMAXCONN)
loopfd = create(EPOLL_CLOEXEC)
add(fd, onConnect)
while (1) poll(-1)
}
spawn(main)
const process = require('process')
const { thread } = just.library('thread')
const processes = {
spawn: main => {
if (just.env()['WORKER']) return main()
const { watch, launch } = process
const processes = []
const cpus = parseInt(just.env().CPUS || just.sys.cpus, 10)
if (cpus === 1) return main()
for (let i = 0; i < cpus; i++) {
just.sys.setenv('WORKER', i)
const proc = launch(just.args[0], just.args.slice(1))
processes.push(proc)
proc.stats = { user: 0, system: 0 }
}
return Promise.all(processes.map(p => watch(p)))
}
}
const threads = {
watch: p => {
return new Promise((resolve) => {
const timer = just.setInterval(() => {
const status = thread.tryJoin(p.tid)
if (status >= 0) {
just.sys.nextTick(() => {
just.clearInterval(timer)
})
resolve(status)
}
}, 100)
})
},
spawn: main => {
if (just.env()['WORKER']) return main()
const processes = []
const cpus = parseInt(just.env().CPUS || just.sys.cpus, 10)
if (cpus === 1) return main()
for (let i = 0; i < cpus; i++) {
just.sys.setenv('WORKER', i)
const tid = thread.spawn(just.main, just.builtin('just.js'), just.args.slice(0))
const proc = { tid }
processes.push(proc)
proc.stats = { user: 0, system: 0 }
}
return Promise.all(processes.map(p => threads.watch(p)))
}
}
function spawn (main, useThreads = !!just.env().JSPT) {
if (useThreads) return threads.spawn(main)
return processes.spawn(main)
}
module.exports = spawn
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment