diff options
-rw-r--r-- | captain/db.f90 | 102 | ||||
-rw-r--r-- | captain/external.f90 | 85 | ||||
-rw-r--r-- | captain/launch.f90 | 6 | ||||
-rw-r--r-- | captain/sqlite.f90 | 51 |
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 |