aboutsummaryrefslogtreecommitdiff
path: root/captain
diff options
context:
space:
mode:
Diffstat (limited to 'captain')
-rw-r--r--captain/config.f9014
-rw-r--r--captain/db.f9056
-rw-r--r--captain/example/levitating.conf4
-rw-r--r--captain/external.f9096
-rw-r--r--captain/gemini.f908
-rw-r--r--captain/levitating-captain.prj3
-rw-r--r--captain/sql/create.sql2
-rwxr-xr-xcaptain/sql/scan_instructions.sh19
-rw-r--r--captain/templates/index.gmi1
9 files changed, 199 insertions, 4 deletions
diff --git a/captain/config.f90 b/captain/config.f90
index 5ab5930..3d23011 100644
--- a/captain/config.f90
+++ b/captain/config.f90
@@ -34,6 +34,12 @@ implicit none
character(*), parameter::STATIC_DIRECTORY_VARIABLE = "static-directory"
character(1024)::static_dir
+ character(*), parameter::INSTRUCTIONS_DIRECTORY_VARIABLE = "instructions-directory"
+ character(1024)::instructions_dir
+
+ character(*), parameter::SCRIPT_DIRECTORY_VARIABLE = "script-directory"
+ character(1024)::script_dir
+
contains
subroutine get_variable(str, v)
@@ -109,7 +115,13 @@ contains
else if(cvariable == STATIC_DIRECTORY_VARIABLE) then
static_dir = cvalue
-
+
+ else if(cvariable == SCRIPT_DIRECTORY_VARIABLE) then
+ script_dir = cvalue
+
+ else if(cvariable == INSTRUCTIONS_DIRECTORY_VARIABLE) then
+ instructions_dir = cvalue
+
end if
end subroutine assign_config
diff --git a/captain/db.f90 b/captain/db.f90
index 2dc1cff..b607c39 100644
--- a/captain/db.f90
+++ b/captain/db.f90
@@ -3,6 +3,7 @@ use sqlite
implicit none
integer, parameter::PLAYER_NAME_LENGTH = 128
+ integer, parameter::FILENAME_NAME_LENGTH = 1024
character(1024)::database_file
type(c_ptr)::db
@@ -135,4 +136,59 @@ contains
end function get_player_names
+ function get_instuctions_count()
+ implicit none
+
+ type(sqlite3_stmt)::stmt
+ integer::get_instuctions_count
+
+ get_instuctions_count = 0
+ if(stmt%prepare(db, "SELECT COUNT(*) FROM instructions") == SQLITE_OK) then
+ if(stmt%step() == SQLITE_ROW) then
+ get_instuctions_count = stmt%column_int(0)
+ end if
+ end if
+ call stmt%finalize()
+
+ end function get_instuctions_count
+
+ function get_instruction_names() result(res)
+ implicit none
+
+ type(sqlite3_stmt)::stmt
+ character(len=PLAYER_NAME_LENGTH), dimension(:), pointer::res
+ integer::i,n
+
+ n = get_instuctions_count()
+ if(n > 0) then
+ allocate(res(n))
+ if(stmt%prepare(db, "SELECT name FROM instructions ORDER BY name") == SQLITE_OK) then
+ i = 1
+ do while(stmt%step() == SQLITE_ROW .and. i <= n)
+ call stmt%column_text(0, res(i))
+ i = i + 1
+ end do
+ end if
+ call stmt%finalize()
+
+ end if
+
+ end function get_instruction_names
+
+ subroutine scan_instructions_for_db()
+ use config
+ use utilities
+ use logging
+ implicit none
+
+ character(len=2048)::cmdline
+
+ call combine_paths(script_dir, "scan_instructions.sh", cmdline)
+ cmdline = trim(cmdline)//" "//trim(database_file)//" "//trim(instructions_dir)//" 1>/dev/null 2>/dev/null"
+
+ call write_log("Scan Command: "//trim(cmdline))
+ call execute_command_line(trim(cmdline), wait=.true.)
+
+ end subroutine scan_instructions_for_db
+
end module captain_db
diff --git a/captain/example/levitating.conf b/captain/example/levitating.conf
index a43ea8d..1b647a4 100644
--- a/captain/example/levitating.conf
+++ b/captain/example/levitating.conf
@@ -18,3 +18,7 @@ uploads-directory = /home/jeff/Workspace/levitating/captain/example/uploads
results-directory = /home/jeff/Workspace/levitating/captain/example/results
static-directory = /home/jeff/Workspace/levitating/captain/example/static
+
+script-directory = /home/jeff/Workspace/levitating/captain/sql
+
+instructions-directory = /home/jeff/Workspace/levitating/captain/example/instructions
diff --git a/captain/external.f90 b/captain/external.f90
index 5e64bab..78195f8 100644
--- a/captain/external.f90
+++ b/captain/external.f90
@@ -49,6 +49,52 @@ contains
end function generate_players_gemini
+ function generate_instructions_gemini() result(res)
+ use captain_db
+ implicit none
+
+ character(len=:), pointer::res
+ character(len=PLAYER_NAME_LENGTH), dimension(:), pointer::instruction_names
+ integer::n, i, nsize
+
+ character(len=3*PLAYER_NAME_LENGTH)::one_player
+
+ n = get_instuctions_count()
+
+ if(n == 0) then
+
+ allocate(character(len=1024) :: res)
+ res = "None Yet"
+
+ else
+
+ instruction_names => get_instruction_names()
+ nsize = 1024
+ do i = 1, size(instruction_names)
+ nsize = nsize + 16 + 2*len_trim(instruction_names(i))
+ end do
+
+ allocate(character(len=nsize) :: res)
+ res = "## Instructions"
+
+ do i = 1, n
+ one_player = "=> /instructions/"//trim(instruction_names(i))//".json "//trim(instruction_names(i))
+ if(i == 1) then
+ res = trim(res)//new_line(res(1:1))//new_line(res(1:1))//trim(one_player)
+ else
+ res = trim(res)//new_line(res(1:1))//trim(one_player)
+ end if
+ end do
+
+ deallocate(instruction_names)
+
+ end if
+
+ res = trim(res)//new_line(res(1:1))//new_line(res(1:1))//"## Management"// &
+ new_line(res(1:1))//"=> /instructions/scan.gmi Scan for Instructions"
+
+ end function generate_instructions_gemini
+
pure function is_input_provided_request(req)
use server_response, only: request
implicit none
@@ -123,10 +169,43 @@ contains
(trim(first) == "uploads") .or. &
(trim(first) == "results") .or. &
(trim(first) == "static") .or. &
- (trim(first) == "favicon.txt"))
+ (trim(first) == "favicon.txt") .or. &
+ (trim(first) == "instructions"))
end function is_request_static
+ function is_redirect_action(req)
+ use server_response
+ implicit none
+
+ class(request), intent(in)::req
+ logical::is_redirect_action
+
+ is_redirect_action = .false.
+ if(req%location == "/instructions/scan.gmi") then
+ is_redirect_action = .true.
+ end if
+
+ end function is_redirect_action
+
+ function external_redirect_action_request_gemini(req) result(resp)
+ use captain_db
+ use server_response
+ use logging
+ implicit none
+
+ class(request), intent(in)::req
+ type(response)::resp
+
+ resp%code = GEMINI_CODE_REDIRECT
+
+ if(req%location == "/instructions/scan.gmi") then
+ call scan_instructions_for_db()
+ call resp%set_url("/instructions.gmi")
+ end if
+
+ end function external_redirect_action_request_gemini
+
function external_request_static(req) result(resp)
use logging, only: write_log
use config
@@ -177,6 +256,9 @@ contains
else if(index(filename, ".txt") /= 0) then
resp%body_mimetype = "text/plain"
+ else if(index(filename, ".json") /= 0) then
+ resp%body_mimetype = "text/plain"
+
! Just a catch-all, whatever...
else
resp%body_mimetype = "application/octet-stream"
@@ -231,6 +313,12 @@ contains
call page%assign('title', 'About')
+ else if(trim(req%location) == "/instructions.gmi") then
+
+ call page%assign('title', 'Build Instructions')
+ contents => generate_instructions_gemini()
+ call page%assign('contents', contents)
+
else
call page%assign('title', 'Not Found')
@@ -259,7 +347,11 @@ contains
class(request), intent(in)::req
type(response)::resp
- if(is_input_provided_request(req)) then
+ if(is_redirect_action(req)) then
+ call write_log("Action request")
+ resp = external_redirect_action_request_gemini(req)
+
+ else if(is_input_provided_request(req)) then
call write_log("Input request")
resp = external_input_request_gemini(req)
diff --git a/captain/gemini.f90 b/captain/gemini.f90
index 0930d17..46725cb 100644
--- a/captain/gemini.f90
+++ b/captain/gemini.f90
@@ -85,6 +85,9 @@ contains
character(1024)::line
write(int_text, '(I8)') code
+ line = trim(adjustl(int_text))//" "//trim(meta)
+ call write_log("Status line: "//trim(line))
+
call write_string(ssl, trim(adjustl(int_text))//" "//trim(meta)//c_carriage_return//c_new_line)
end subroutine write_status
@@ -290,6 +293,11 @@ contains
call req%destroy()
call resp%destroy()
+
+
+ res = ssl_shutdown(ssl)
+ res = ssl_free(ssl)
+ res = ctx_free(ctx)
end subroutine handle_request
diff --git a/captain/levitating-captain.prj b/captain/levitating-captain.prj
index 1fe6cc8..31841f9 100644
--- a/captain/levitating-captain.prj
+++ b/captain/levitating-captain.prj
@@ -39,6 +39,9 @@
"Files":[{
"filename":"sql/create.sql",
"enabled":"1"
+ },{
+ "filename":"sql/scan_instructions.sh",
+ "enabled":"1"
}]
},{
"Folders":[],
diff --git a/captain/sql/create.sql b/captain/sql/create.sql
index 9fd00d0..e8198e4 100644
--- a/captain/sql/create.sql
+++ b/captain/sql/create.sql
@@ -5,7 +5,7 @@ CREATE TABLE jobs(id INTEGER PRIMARY KEY, player INTEGER DEFAULT NULL, status IN
CREATE TABLE tasks(job INTEGER, task INTEGER, status INTEGER, FOREIGN KEY(job) REFERENCES jobs(id));
-CREATE TABLE instructions(id INTEGER PRIMARY KEY, name TEXT NOT NULL, file TEXT NOT NULL);
+CREATE TABLE instructions(id INTEGER PRIMARY KEY, name TEXT UNIQUE NOT NULL);
CREATE_TABLE available(instruction INTEGER, player INTEGER, \
FOREIGN KEY(instruction) REFERENCES instructions(id), \
diff --git a/captain/sql/scan_instructions.sh b/captain/sql/scan_instructions.sh
new file mode 100755
index 0000000..dab98b3
--- /dev/null
+++ b/captain/sql/scan_instructions.sh
@@ -0,0 +1,19 @@
+#!/usr/bin/env bash
+
+cmds=`tempfile`
+echo $cmds
+
+for filename in $2/*.json; do
+ # In case it doesn't exist
+ [ -e "$filename" ] || continue
+ name=${filename##*/}
+ echo $name
+ base=${name%.json}
+ echo $base
+
+ echo "INSERT OR IGNORE INTO instructions(name) VALUES('$base');" | cat >> $cmds
+done
+
+sqlite3 $1 < $cmds
+
+rm $cmds
diff --git a/captain/templates/index.gmi b/captain/templates/index.gmi
index ebc7419..bbcd8d2 100644
--- a/captain/templates/index.gmi
+++ b/captain/templates/index.gmi
@@ -7,6 +7,7 @@ The Levitating Captain interface for the {{ project }} project.
=> /releases.gmi Releases
=> /jobs.gmi Jobs
=> /players.gmi Players
+=> /instructions.gmi Instructions
=> /about.gmi About
{{ contents }}