toymaker.git

commit eeef381610f358b08bfd6658a5fe65830817fa49

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/