Author: Adam <git@apiote.xyz>
initial commit
build_images.sh | 13 ++ get.sh | 16 +++ server2.sh | 234 +++++++++++++++++++++++++++++++++++++++++++++++++++ start.sh | 31 ++++++ todo | 10 ++
diff --git a/build_images.sh b/build_images.sh new file mode 100644 index 0000000000000000000000000000000000000000..d70c435aed2083e2835b6b0ea81db4e7a863a917 --- /dev/null +++ b/build_images.sh @@ -0,0 +1,13 @@ +#!/bin/sh + +podman container prune -f +podman image prune -f + +cd ~/blueprints || exit 1 + +if git status >/dev/null 2>&1 +then + git pull +fi + +find . -maxdepth 1 -mindepth 1 -type d -exec sh -c 'podman build -t "toy_$(basename "$1")" $1' shell {} \; diff --git a/get.sh b/get.sh new file mode 100644 index 0000000000000000000000000000000000000000..d6fcdb6f6a9e9b49c289fe2413ee5ac1acf9b5fd --- /dev/null +++ b/get.sh @@ -0,0 +1,16 @@ +#!/bin/sh + +list_toys() { + find toys/ -mindepth 1 -maxdepth 1 -type d +} + +list_items() { + toy=$1 + find "toys/$toy" . -mindepth 1 -maxdepth 1 -type d +} + +show_item() { + toy=$1 + item=$2 + cat "toys/$toy/$item.log" +} diff --git a/server2.sh b/server2.sh new file mode 100755 index 0000000000000000000000000000000000000000..8c610376f46362ea79b5f06ed1b407be79956a98 --- /dev/null +++ b/server2.sh @@ -0,0 +1,234 @@ +#!/bin/sh +# +# Based on server by Upper Stream (c) 2017, MIT license + +. start.sh +. get.sh + +set -e + +# program name +program=${0##*/} + +usage() { + cat <<-EOF + Usage: + + $program [-p port] [docroot] + $program -h + + -p port : specify listening port number; defaults to 10080 + -h : print this help and quit + docroot : specify document root directory; defaults to the current directory +EOF +} + +# default listening port +port=10080 + +# Configure in accordance with your environment +nc=$(command -v nc) || true + +pid_file=/tmp/$program.pid + +slashes() { + printf "%s" "$1" | sed 's|[^/]||g' | wc -m +} + +field() { + echo "$1" | cut -d '/' -f "$2" +} +makefifo() { + name="$1" + mkfifo -m 0600 "/tmp/$name.fifo" && echo "/tmp/$name.fifo" +} + + +respond200() { + page="$1" + + { cat "$fifo2" > /dev/null; printf ""; } > "$fifo1" & + + printf "HTTP/1.1 200 OK\r\nContent-Length: %s\r\nContent-Type: text/html\r\n\r\n" "${#page}" >> "$fifo1" + + printf "%s\r\n" "$page" >> "$fifo1" + + sleep 1; echo "end" > "$fifo2" + printf "200 %s" "${#page}" +} + +respond201() { + toy=$1 + item=$2 + # todo template + message="" + printf "HTTP/1.1 201 Created\r\nContent-Length: %s\r\nLocation: /toys/%s/%s\r\n\r\n%s\r\n" "${#message}" "$name" "$item" "$message" > "$fifo1" + printf "201 -" +} + +respond404() { + path=$1 + # todo template + message="$path not found" + printf "HTTP/1.1 404 Not Found\r\nContent-Length: %s\r\n\r\n%s\r\n" "${#message}" "$message" > "$fifo1" + printf "404 -" +} + +respond405() { + message="$1 unsupported" + printf "HTTP/1.1 405 Method Not Allowed\r\nContent-Length: %s\r\n\r\n%s\r\n" "${#message}" "$message" > "$fifo1" + printf "405 -" +} + +respond500() { + # todo template + message="Server error: $1" + printf "HTTP/1.1 500 Internal Server Error\r\nContent-Length: %s\r\n\r\n%s\r\n" "${#message}" "$message" > "$fifo1" + printf "500 -" +} + +execute() { + method="$1" + path="$2" + toys=$(field "$path" 2) + if [ "$toys" != 'toys' ] + then + respond404 "$path" + fi + + case $method in + GET) + if [ "$(slashes "$path")" -eq 2 ] + then + toy=$(field "$path" 3) + if [ "$toy" = '' ] + then + page=$(list_toys) + respond200 "$page" + else + page=$(list_items "$toy") + # todo if $toy not found -> 404 + respond200 "$page" + fi + elif [ "$(slashes "$path")" -eq 2 ] + then + toy=$(field "$path" 3) + item=$(field "$path" 4) + page=$(show_item "$toy" "$item") + # todo if $toy or $toy/$item not found -> 404 + respond200 "$page" + else + respond404 "$path" + fi + ;; + POST) + toy=$(field "$path" 3) + if [ "$(slashes "$path")" -ne 3 ] || [ -n "$(field "$path" 4)" ] + then + respond404 "$path" + fi + + item=$(post_item "$toy") + if [ $! -gt 0 ] + then + respond500 "error while creating $toy" + else + respond201 "$toy" "$item" + fi + ;; + *) + respond405 "$method" + ;; + esac +} + +cleanup() { + rm "$fifo1" "$fifo2" "$pid_file" +} + +interrupt() { + cleanup + exit 0 +} + +parse() { + cr=$(printf "\r") + while read -r line; do + line="${line%"$cr"}" + case "$line" in + GET*|POST*|PUT*|DELETE*) + # shellcheck disable=SC2086 + set -- $line + method=$1 + path=$2 + ;; + Host:*) + host=${line#Host: } + ;; + # Authorization + *:*) + ;; + "") + date=$(date +'%d/%m/%Y:%H:%M:%S %z') + status_length=$(execute "$method" "$path") + printf "%s %s \"http://%s%s\" %s\n" "$date" "$method" "$host" "$path" "$status_length" + trap - INT + exit + ;; + *) + ;; + esac + done +} + +# dependency verification +for cmd in nc; do + command -v $cmd >/dev/null || { echo "$0: \`$cmd\` not found"; exit 2; } +done + +while getopts p:h opt; do + case $opt in + p) port=$OPTARG;; + h) usage; exit 255;; + *) usage; exit 255;; + esac +done +shift $((OPTIND-1)) + +if [ $# -eq 0 ]; then + docroot=. +else + docroot="$1" +fi +docroot=$(cd "$docroot"; pwd) + +# FIFO to write HTTP response ## todo mktemp +if ! fifo1=$(makefifo "${0##*/}.$$.1"); then + echo "$0: creating a named pipe failed. Already running?" 1>&2 + exit 1 +fi + +# FIFO for internal event notification ## todo mktemp +if ! fifo2=$(makefifo "${0##*/}.$$.2"); then + echo "$0: creating a named pipe failed. Already running?" 1>&2 + exit 1 +fi + +trap interrupt INT + +echo $$ > "$pid_file" + +cat 1>&2 <<EOF +Simple HTTP Server + +Listening at the port number $port. +Type ^C to quit. +EOF + +# todo nc error should crash +# shellcheck disable=SC2002 +while cat "$fifo1" | "$nc" -l "$port" | parse; do + : +done +cleanup +exit diff --git a/start.sh b/start.sh new file mode 100644 index 0000000000000000000000000000000000000000..269e04292e2e69383c6a6dde41cb48baecb0c6b0 --- /dev/null +++ b/start.sh @@ -0,0 +1,31 @@ +#!/bin/sh + +post_item() { + toy=$1 + + mkdir -p "toys/$toy/" + while ! mkdir "toys/$toy/.lock" + do + sleep 1 + pid=$(cat "toys/$toy/.lock/pid") + if [ -n "$pid" ] && ! kill -0 "$pid" + then + rm -r "toys/$toy/.lock" + fi + done + + echo $$ >"toys/$toy/.lock/pid" + set -e + lastItem=$(find "toys/$toy/" -type d -maxdepth 1 -mindepth 1 | sort -n | tail -n 1) + lastItem=${lastItem:--1} + currentItem=$(( lastItem + 1 )) + mkdir "toys/$toy/$currentItem" + rm -r "toys/$toy/.lock" + + ( + podman run --rm "toy_$toy" >"/toys/$toy/$currentItem.log" 2>&1 + echo $? >"toys/$toy/$currentItem.exit" + ) & + + printf "%s" "$currentItem" +} diff --git a/todo b/todo new file mode 100644 index 0000000000000000000000000000000000000000..4a931d746455491497d6ea3b90a8f9246b004a6a --- /dev/null +++ b/todo @@ -0,0 +1,10 @@ +POST /toys/$name/ + Header:: Authorization: Bearer $secret +GET /toys/ + => html list of toys +GET /toys/$name + => html list of toy's items +GET /toys/$name/$id + => logs of item + +container gets ARG $number and must put artifact in ~/toys/$name/$number/