aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--captain/db.f90102
-rw-r--r--captain/external.f9085
-rw-r--r--captain/launch.f906
-rw-r--r--captain/sqlite.f9051
4 files changed, 226 insertions, 18 deletions
diff --git a/captain/db.f90 b/captain/db.f90
index 1060dbc..c23b770 100644
--- a/captain/db.f90
+++ b/captain/db.f90
@@ -8,6 +8,7 @@ implicit none
integer, parameter::JOB_STATUS_SUCCESS = 1
integer, parameter::JOB_STATUS_FAILURE = 2
integer, parameter::JOB_STATUS_WORKING = 3
+ integer, parameter::JOB_STATUS_PENDING = 0
integer, parameter::PLAYER_STATUS_BUSY = JOB_STATUS_WORKING
integer, parameter::PLAYER_STATUS_IDLE = 100
@@ -25,6 +26,14 @@ implicit none
end type
+ type :: task
+
+ integer::job
+ integer::number
+ integer::status
+
+ end type
+
interface is_player_busy
module procedure is_player_busy_by_id
module procedure is_player_busy_by_name
@@ -358,7 +367,11 @@ contains
jobs(i)%instruction = id
jobs(i)%player = stmt%column_int(1)
jobs(i)%status = stmt%column_int(2)
- call stmt%column_text(3, jobs(i)%time)
+ if(stmt%column_type(3) == SQLITE_NULL) then
+ jobs(i)%time = "Not started"
+ else
+ call stmt%column_text(3, jobs(i)%time)
+ end if
i = i + 1
end do
end if
@@ -468,6 +481,93 @@ contains
end subroutine remove_player_for_instruction
+ subroutine add_new_job(instruction, player)
+ implicit none
+
+ integer, intent(in)::instruction, player
+ type(sqlite3_stmt)::stmt
+
+ if(stmt%prepare(db, "INSERT INTO jobs(instruction, player, status) VALUES(?, ?, ?)") == SQLITE_OK) then
+ if(stmt%bind_int(1, instruction) == SQLITE_OK .and. &
+ stmt%bind_int(2, player) == SQLITE_OK .and. &
+ stmt%bind_int(3, JOB_STATUS_PENDING) == SQLITE_OK) then
+ call stmt%step_now()
+ end if
+ end if
+ call stmt%finalize()
+
+ end subroutine add_new_job
+
+ function get_job(id)
+ implicit none
+
+ integer, intent(in)::id
+ type(job)::get_job
+ type(sqlite3_stmt)::stmt
+
+ get_job%id = -1
+
+ if(stmt%prepare(db, "SELECT instruction,player,status,time FROM jobs WHERE id=?") == SQLITE_OK) then
+ if(stmt%bind_int(1, id) == SQLITE_OK) then
+ if(stmt%step() == SQLITE_ROW) then
+ get_job%instruction = stmt%column_int(0)
+ get_job%player = stmt%column_int(1)
+ get_job%player = stmt%column_int(2)
+ if(stmt%column_type(3) == SQLITE_NULL) then
+ get_job%time = "Not started"
+ else
+ call stmt%column_text(3,get_job%time)
+ end if
+ get_job%id = id
+ end if
+ end if
+ end if
+ call stmt%finalize()
+
+ end function get_job
+
+ function get_job_tasks(job) result(res)
+ implicit none
+
+ integer, intent(in)::job
+ type(task), dimension(:), pointer::res
+
+ type(sqlite3_stmt)::stmt
+ integer::n, i
+
+ n = 0
+ if(stmt%prepare(db, "SELECT COUNT(*) FROM tasks WHERE job=?") == SQLITE_OK) then
+ if(stmt%bind_int(1, job) == SQLITE_OK) then
+ if(stmt%step() == SQLITE_ROW) then
+ n = stmt%column_int(0)
+ end if
+ end if
+ end if
+ call stmt%finalize()
+
+ if(n == 0) then
+ res => null()
+
+ else
+ allocate(res(n))
+ res%number = 0
+ res%status = JOB_STATUS_PENDING
+ if(stmt%prepare(db, "SELECT task, status FROM tasks WHERE job=? ORDER BY task ASC") == SQLITE_OK) then
+ if(stmt%bind_int(1, job) == SQLITE_OK) then
+ i = 1
+ do while(stmt%step() == SQLITE_ROW .and. i <= n)
+ res(i)%number = stmt%column_int(0)
+ res(i)%status = stmt%column_int(1)
+ res(i)%job = job
+ i = i + 1
+ end do
+ end if
+ end if
+ call stmt%finalize()
+ end if
+
+ end function get_job_tasks
+
subroutine scan_instructions_for_db()
use config
use utilities
diff --git a/captain/external.f90 b/captain/external.f90
index d572a7e..a86bd52 100644
--- a/captain/external.f90
+++ b/captain/external.f90
@@ -28,6 +28,10 @@ contains
! Sleeping 0x1f4a4
res = char(240)//char(159)//char(146)//char(164)
+ case(JOB_STATUS_PENDING)
+ ! Envelope 0x2709
+ res = char(226)//char(156)//char(137)//" "
+
end select
end function get_status_utf8
@@ -61,7 +65,7 @@ contains
last = min(size(jobs), stopindex)
end if
- if(first < last .and. first < size(jobs)) then
+ if(first <= last .and. first <= size(jobs)) then
nsize = (last-first+1)*(2*PLAYER_NAME_LENGTH + 64)
allocate(character(len=nsize) :: res)
res = " "
@@ -71,7 +75,7 @@ contains
call get_player_name(jobs(i)%player, player)
write(int_text, '(I8)') jobs(i)%id
- link = "=> jobs/"//trim(adjustl(int_text))//".gmi"// &
+ link = "=> jobs/"//trim(adjustl(int_text))//".gmi "// &
trim(get_status_utf8(jobs(i)%status))//" Job "// &
trim(adjustl(int_text))//" - "//trim(instruction)
@@ -96,17 +100,17 @@ contains
function generate_jobs_gemini(req) result(res)
use captain_db
use server_response
+ use logging
implicit none
type(request)::req
character(len=:), pointer::res
type(job), dimension(:), pointer::jobs
- integer::n, i, nsize
+ integer::n, nsize
integer::i_start_jobs, ierr
character(len=:), pointer::linklist
- character(16)::int_text, int_text2
-
+ character(64)::dbgstr
n = get_jobs_count()
if(n == 0) then
@@ -134,13 +138,80 @@ contains
res = "## Jobs "
+ write(dbgstr, '(I3,1X,I3)') i_start_jobs, min(i_start_jobs+14, n)
+ call write_log("Jobs between "//trim(dbgstr))
+
linklist => render_jobs_links(jobs, i_start_jobs, min(i_start_jobs+14, n))
- res = res//trim(linklist)
+ res = trim(res)//trim(linklist)
+ call write_log(linklist)
deallocate(linklist)
end if
end function generate_jobs_gemini
+
+ function generate_one_job_gemini(req) result(res)
+ use captain_db
+ use server_response
+ implicit none
+
+ type(request), intent(in)::req
+ character(len=:), pointer::res
+
+ character(4)::status
+ integer::i, j, job_id
+ type(job)::one_job
+
+ character(PLAYER_NAME_LENGTH)::player
+ character(1)::nl = new_line(' ')
+
+ type(task), dimension(:), pointer::tasks
+ character(16)::task_text, job_text
+
+ res => null()
+
+ i = index(req%location, "/", back=.true.)
+ j = index(req%location, ".", back=.true.)
+
+ job_text = req%location(i+1:j-1)
+ read(job_text, *) job_id
+ one_job = get_job(job_id)
+
+ if(one_job%id >= 0) then
+ allocate(character(len=1024) :: res)
+
+ status = get_status_utf8(one_job%status)
+ res = "## Job "//job_text//" - "//status
+
+ call get_player_name(one_job%player, player)
+ res = trim(res)//nl//nl//"Running on "//trim(player)//nl//"Last update at: "//one_job%time
+
+ res = trim(res)//nl//nl//"### Task Results"
+
+ tasks => get_job_tasks(job_id)
+ if(associated(tasks)) then
+ do i = 1, size(tasks)
+ status = get_status_utf8(tasks(i)%status)
+ write(task_text, '(I8)') tasks(i)%number
+
+ res = trim(res)//nl//"=> /results/"//trim(job_text)//"-"//trim(adjustl(task_text))//".txt "// &
+ trim(status)//"Task "//trim(adjustl(task_text))
+
+ end do
+ deallocate(tasks)
+ else
+ res = trim(res)//nl//nl//"None reported yet"
+ end if
+
+ else
+
+ allocate(character(len=64) :: res)
+ write(res, '(A20, 1X, I5)') "No record of:", job_id
+
+ end if
+
+
+ end function generate_one_job_gemini
function generate_players_gemini() result(res)
use captain_db
@@ -203,7 +274,7 @@ contains
character(len=PLAYER_NAME_LENGTH), dimension(:), pointer::all_players
integer::i, j, n_jobs, n_players, nsize
- character(len=:), pointer::job_link_text, player_link_text
+ character(len=:), pointer::job_link_text
character(1)::nl = new_line(' ')
character(PLAYER_NAME_LENGTH)::player_name
character(4)::player_status
diff --git a/captain/launch.f90 b/captain/launch.f90
index 97e0a59..8a074a5 100644
--- a/captain/launch.f90
+++ b/captain/launch.f90
@@ -4,9 +4,15 @@ implicit none
contains
subroutine launch_instructions_on_player(instruction, player)
+ use captain_db
implicit none
character(*), intent(in)::instruction, player
+ integer::instruction_id, player_id
+
+ instruction_id = get_instruction_id(instruction)
+ player_id = get_player_id(player)
+ call add_new_job(instruction_id, player_id)
end subroutine launch_instructions_on_player
diff --git a/captain/sqlite.f90 b/captain/sqlite.f90
index 003bd6f..a1d4a4c 100644
--- a/captain/sqlite.f90
+++ b/captain/sqlite.f90
@@ -7,7 +7,13 @@ implicit none
integer(kind=c_int), parameter::SQLITE_BUSY = 5
integer(kind=c_int), parameter::SQLITE_ROW = 100
integer(kind=c_int), parameter::SQLITE_DONE = 101
-
+
+ integer(kind=c_int), parameter::SQLITE_INTEGER = 1
+ integer(kind=c_int), parameter::SQLITE_FLOAT = 2
+ integer(kind=c_int), parameter::SQLITE_TEXT = 3
+ integer(kind=c_int), parameter::SQLITE_BLOB = 4
+ integer(kind=c_int), parameter::SQLITE_NULL = 5
+
integer, parameter::sqlite3_max_free_strings = 32
interface
@@ -110,6 +116,13 @@ implicit none
integer(c_int)::sqlite3_step
end function sqlite3_step
+ function sqlite3_column_type(p, c) bind(c, name='sqlite3_column_type')
+ use iso_c_binding
+ type(c_ptr), value::p
+ integer(kind=c_int), value::c
+ integer(c_int)::sqlite3_column_type
+ end function sqlite3_column_type
+
end interface
type :: sqlite3_stmt
@@ -129,6 +142,7 @@ implicit none
procedure::step_now => stmt_step_ignore
procedure::column_int => stmt_column_int
procedure::column_text => stmt_column_text
+ procedure::column_type => stmt_column_type
end type
@@ -294,10 +308,25 @@ contains
integer, intent(in)::i
integer::stmt_column_int
- stmt_column_int = c_sqlite3_column_int(self%stmt, i)
+ if(self%column_type(i) /= SQLITE_NULL) then
+ stmt_column_int = c_sqlite3_column_int(self%stmt, i)
+ else
+ stmt_column_int = -1*huge(1)
+ end if
end function stmt_column_int
+ function stmt_column_type(self, i)
+ implicit none
+
+ class(sqlite3_stmt), intent(inout)::self
+ integer, intent(in)::i
+ integer::stmt_column_type
+
+ stmt_column_type = sqlite3_column_type(self%stmt, i)
+
+ end function stmt_column_type
+
subroutine stmt_column_text(self, i, res)
implicit none
@@ -307,17 +336,19 @@ contains
character(kind=c_char), dimension(:), pointer::src
type(c_ptr)::txtcol
- integer::n, i_char
+ integer(kind=8)::n, i_char
- txtcol = c_sqlite3_column_text(self%stmt, i)
res = " "
- if(c_associated(txtcol)) then
- n = c_strlen(txtcol)
- call c_f_pointer(txtcol, src, (/ n /))
- do i_char=1, min(n, len(res))
- res(i_char:i_char) = src(i_char)
- end do
+ if(self%column_type(i) /= SQLITE_NULL) then
+ txtcol = c_sqlite3_column_text(self%stmt, i)
+ if(c_associated(txtcol)) then
+ n = c_strlen(txtcol)
+ call c_f_pointer(txtcol, src, (/ n /))
+ do i_char=1, min(n, len(res))
+ res(i_char:i_char) = src(i_char)
+ end do
+ end if
end if
end subroutine stmt_column_text