382 lines
		
	
	
		
			11 KiB
		
	
	
	
		
			Nim
		
	
	
	
	
	
			
		
		
	
	
			382 lines
		
	
	
		
			11 KiB
		
	
	
	
		
			Nim
		
	
	
	
	
	
# --==--==--==--==--==--==--==--==--==--==--==--==--==--==--==-- #
 | 
						|
# Bruno Charest 
 | 
						|
# 2022-08-09 
 | 
						|
# 
 | 
						|
# __ DESCRIPTIONS __
 | 
						|
# joplin_utils : procedure related joplin application 
 | 
						|
#
 | 
						|
# --==--==--==--==--==--==--==--==--==--==--==--==--==--==--==-- #
 | 
						|
import net
 | 
						|
import times
 | 
						|
import osproc
 | 
						|
import jester
 | 
						|
import std/json
 | 
						|
import httpcore
 | 
						|
import strutils
 | 
						|
import strformat
 | 
						|
import std/options
 | 
						|
from os import sleep
 | 
						|
import std/[asyncdispatch, httpclient]
 | 
						|
 | 
						|
# --==--==--==--==--==--==--==--==--==--==-- #
 | 
						|
# TYPE : Setup joplin_ping data
 | 
						|
# --==--==--==--==--==--==--==--==--==--==-- #
 | 
						|
type
 | 
						|
  joplin_ping* = object
 | 
						|
    ping_result*: seq[string]
 | 
						|
    ping_status*: bool
 | 
						|
    req*: Request
 | 
						|
 | 
						|
# --==--==--==--==--==--==--==--==--==--==-- #
 | 
						|
# TYPE : Setup joplin_tags data
 | 
						|
# --==--==--==--==--==--==--==--==--==--==-- #
 | 
						|
type
 | 
						|
  joplin_tags* = object
 | 
						|
    id*, parent_id*, title*: seq[string]
 | 
						|
    created_time*, updated_time*, user_created_time*, user_updated_time*, is_shared*: seq[int] 
 | 
						|
    req*: Request
 | 
						|
 | 
						|
# --==--==--==--==--==--==--==--==--==--==-- #
 | 
						|
# TYPE : Setup joplin_notebooks data
 | 
						|
# --==--==--==--==--==--==--==--==--==--==-- #
 | 
						|
type
 | 
						|
  joplin_notebooks* = object    
 | 
						|
    id*, parent_id*, title*, share_id*, icon*: seq[string]
 | 
						|
    created_time*, updated_time*, user_created_time*, user_updated_time*, is_shared*: seq[int] 
 | 
						|
    req*: Request
 | 
						|
 | 
						|
 | 
						|
# --==--==--==--==--==--==--==--==--==--==-- #
 | 
						|
# TYPE : Setup joplin_notes data
 | 
						|
# --==--==--==--==--==--==--==--==--==--==-- #
 | 
						|
type
 | 
						|
  joplin_notes* = object    
 | 
						|
    id*, parent_id*, title*, body*, author*, source_url*, source*, source_application*, application_data*, share_id*, conflict_original_id*, body_html*, base_url*: seq[string]
 | 
						|
    created_time*, updated_time*, is_conflict*, is_todo*, todo_due*, todo_completed*, user_created_time*, user_updated_time*, markup_language*, is_shared*: seq[int]
 | 
						|
    latitude*, longitude*, altitude*, order*:seq[float] 
 | 
						|
    req*: Request
 | 
						|
 | 
						|
# --==--==--==--==--==--==--==--==--==--==-- #
 | 
						|
# DURATION : duration variables
 | 
						|
# --==--==--==--==--==--==--==--==--==--==-- #
 | 
						|
let
 | 
						|
  resetDuration = initDuration(seconds=2)
 | 
						|
  deciSecondDuration* = initDuration(milliseconds = 100)
 | 
						|
  qtrsecondDuration* = initDuration(milliseconds = 250)
 | 
						|
 | 
						|
# --==--==--==--==--==--==--==--==--==--==-- #
 | 
						|
# VAR : connexion http variables
 | 
						|
# --==--==--==--==--==--==--==--==--==--==-- #
 | 
						|
var
 | 
						|
  client = newHttpClient()
 | 
						|
  lastConnection = getTime().utc
 | 
						|
 | 
						|
 | 
						|
# --==--==--==--==--==--==--==--==--==--==-- #
 | 
						|
# PROC : reset HTTP client 
 | 
						|
# --==--==--==--==--==--==--==--==--==--==-- #
 | 
						|
proc resetHttpClient() =
 | 
						|
  if (getTime().utc - lastConnection) > resetDuration:
 | 
						|
    # Probably a new timeout. We have not yet experienced a long outage.
 | 
						|
    # We may however be entering an extended outage.
 | 
						|
    # Creating the new clients seems to use up lots of CPU.
 | 
						|
    # I want to do that as little as possible.
 | 
						|
    try:
 | 
						|
      client.close()
 | 
						|
    except:
 | 
						|
      echo("Attempted to close clients. Probably do not exist.")
 | 
						|
      echo("Current exception:  ", getCurrentExceptionMsg())
 | 
						|
    client = newHttpClient(timeout=500)
 | 
						|
 | 
						|
# --==--==--==--==--==--==--==--==--==--==--==--==--==-==--==--==- #
 | 
						|
# PROC : use the joplin API ping to validate service availibility
 | 
						|
# --==--==--==--==--==--==--==--==--==--==--==--==--==-==--==--==- #
 | 
						|
proc ping_joplin*(token:string): Future[joplin_ping] {.async.} =
 | 
						|
    
 | 
						|
  var j_p: joplin_ping
 | 
						|
  var client = newAsyncHttpClient()
 | 
						|
  var url: string
 | 
						|
  j_p.ping_status = false
 | 
						|
  try:
 | 
						|
    url = fmt"http://localhost:41184/ping?token={token}"
 | 
						|
    var json = await client.getContent(url)
 | 
						|
    j_p.ping_result.add(json)
 | 
						|
    
 | 
						|
    echo j_p.ping_result[0]
 | 
						|
 | 
						|
    if j_p.ping_result[0] == "JoplinClipperServer":
 | 
						|
      j_p.ping_status = true
 | 
						|
 | 
						|
  except TimeoutError, IOError, OSError:
 | 
						|
    # I naively think I would see this thrown or the plain except below.
 | 
						|
    # But I almost never see an Error raised.
 | 
						|
    echo("Current Exception: ", getCurrentException().name)
 | 
						|
    echo("Current Exception Msg: ", getCurrentExceptionMsg())
 | 
						|
    echo("Sleeping for 1 seconds at: ", getTime().utc)
 | 
						|
    sleep(500)
 | 
						|
    resetHttpClient()
 | 
						|
    j_p.ping_status = false
 | 
						|
  except:
 | 
						|
    echo("Current Exception: ", getCurrentException().name)
 | 
						|
    echo("Current Exception Msg: ", getCurrentExceptionMsg())
 | 
						|
    echo("Sleeping for 1 seconds at: ", getTime().utc)
 | 
						|
    j_p.ping_status = false  
 | 
						|
  return j_p
 | 
						|
    # parse jason
 | 
						|
    #let joplin_notes_Json = parseJson(json)
 | 
						|
 | 
						|
 | 
						|
# --==--==--==--==--==--==--==--==--==--==-- #
 | 
						|
# PROC : get all joplin NOTEBOOKS
 | 
						|
# --==--==--==--==--==--==--==--==--==--==-- #
 | 
						|
proc get_joplin_notebooks*(token:string): Future[joplin_notebooks] {.async.} =
 | 
						|
  
 | 
						|
  # Variables
 | 
						|
  var j_nb: joplin_notebooks
 | 
						|
  var has_more: bool = true
 | 
						|
  var page: int = 1
 | 
						|
  var url: string
 | 
						|
  var client = newAsyncHttpClient()
 | 
						|
  var pingCheck: joplin_ping
 | 
						|
  
 | 
						|
  pingCheck = waitFor ping_joplin(token)
 | 
						|
 | 
						|
  # check the joplin status befor query 
 | 
						|
  if pingCheck.ping_status:
 | 
						|
 | 
						|
    # make sure to check all pages 
 | 
						|
    while has_more == true:
 | 
						|
      
 | 
						|
      # request joplin API for notebooks
 | 
						|
      url = fmt"http://localhost:41184/folders?page={page}&token={token}"
 | 
						|
      echo("URL notebooks : ", url)
 | 
						|
      var json = await client.getContent(url)
 | 
						|
 | 
						|
      # parse jason
 | 
						|
      let joplin_notebooks_Json = parseJson(json)
 | 
						|
 | 
						|
      # valider qu'il n'y a plus de page 
 | 
						|
      if not joplin_notebooks_Json["has_more"].getBool:
 | 
						|
        has_more = false 
 | 
						|
      
 | 
						|
      # store json info into an object
 | 
						|
      var count: int = 1
 | 
						|
      for nb in joplin_notebooks_Json["items"]:
 | 
						|
        j_nb.id.add(nb["id"].getstr)
 | 
						|
        j_nb.parent_id.add(nb["parent_id"].getstr)
 | 
						|
        j_nb.title.add(nb["title"].getstr)
 | 
						|
        count += 1
 | 
						|
      
 | 
						|
      # aller à la page suivante
 | 
						|
      page += 1    
 | 
						|
 | 
						|
  return j_nb
 | 
						|
 | 
						|
 | 
						|
# --==--==--==--==--==--==--==--==--==--==-- #
 | 
						|
# PROC : get all joplin NOTES 
 | 
						|
# --==--==--==--==--==--==--==--==--==--==-- #
 | 
						|
proc get_joplin_notes*(token:string): Future[joplin_notes] {.async.} =
 | 
						|
  
 | 
						|
  # Variables
 | 
						|
  var j_notes: joplin_notes
 | 
						|
  var has_more: bool = true
 | 
						|
  var page: int = 1
 | 
						|
  var url: string
 | 
						|
  var client = newAsyncHttpClient()
 | 
						|
  var pingCheck: joplin_ping
 | 
						|
  pingCheck = waitFor ping_joplin(token)
 | 
						|
 | 
						|
  # check the joplin status befor query 
 | 
						|
  if pingCheck.ping_status:
 | 
						|
 | 
						|
    # make sure to check all pages 
 | 
						|
    while has_more == true:
 | 
						|
      
 | 
						|
      # request joplin API for Notes
 | 
						|
      url = fmt"http://localhost:41184/notes?page={page}&token={token}"
 | 
						|
      echo("URL notes : ", url)
 | 
						|
      var json = await client.getContent(url)
 | 
						|
 | 
						|
      # parse jason
 | 
						|
      let joplin_notes_Json = parseJson(json)
 | 
						|
 | 
						|
      # valider qu'il n'y a plus de page 
 | 
						|
      if not joplin_notes_Json["has_more"].getBool:
 | 
						|
        has_more = false 
 | 
						|
      
 | 
						|
      # store json info into an object
 | 
						|
      var count: int = 1
 | 
						|
      for nb in joplin_notes_Json["items"]:
 | 
						|
        j_notes.id.add(nb["id"].getstr)
 | 
						|
        j_notes.parent_id.add(nb["parent_id"].getstr)
 | 
						|
        j_notes.title.add(nb["title"].getstr)
 | 
						|
        count += 1
 | 
						|
      
 | 
						|
      # aller à la page suivante
 | 
						|
      page += 1    
 | 
						|
 | 
						|
  return j_notes
 | 
						|
 | 
						|
 | 
						|
# --==--==--==--==--==--==--==--==--==--==-- #
 | 
						|
# PROC : get all joplin TAGS
 | 
						|
# --==--==--==--==--==--==--==--==--==--==-- #
 | 
						|
proc get_joplin_tags*(token:string): Future[joplin_tags] {.async.} =
 | 
						|
  
 | 
						|
  # Variables
 | 
						|
  var j_tags: joplin_tags
 | 
						|
  var has_more: bool = true
 | 
						|
  var page: int = 1
 | 
						|
  var url: string
 | 
						|
  var client = newAsyncHttpClient()
 | 
						|
  var pingCheck: joplin_ping
 | 
						|
  pingCheck = waitFor ping_joplin(token)
 | 
						|
 | 
						|
  # check the joplin status befor query 
 | 
						|
  if pingCheck.ping_status:
 | 
						|
 | 
						|
    # make sure to check all pages 
 | 
						|
    while has_more == true:
 | 
						|
      
 | 
						|
      # request joplin API for notebooks
 | 
						|
      url = fmt"http://localhost:41184/tags?page={page}&token={token}"
 | 
						|
      echo("URL tags : ", url)
 | 
						|
      var json = await client.getContent(url)
 | 
						|
 | 
						|
      # parse jason
 | 
						|
      let joplin_tags_Json = parseJson(json)
 | 
						|
 | 
						|
      # valider qu'il n'y a plus de page 
 | 
						|
      if not joplin_tags_Json["has_more"].getBool:
 | 
						|
        has_more = false 
 | 
						|
      
 | 
						|
      # store json info into an object
 | 
						|
      var count: int = 1
 | 
						|
      for nb in joplin_tags_Json["items"]:
 | 
						|
        j_tags.id.add(nb["id"].getstr)
 | 
						|
        j_tags.parent_id.add(nb["parent_id"].getstr)
 | 
						|
        j_tags.title.add(nb["title"].getstr)
 | 
						|
        count += 1
 | 
						|
      
 | 
						|
      # aller à la page suivante
 | 
						|
      page += 1    
 | 
						|
 | 
						|
  return j_tags
 | 
						|
 | 
						|
 | 
						|
# --==--==--==--==--==--==--==--==--==--==-- #
 | 
						|
# PROC : get the token from Joplin Terminal
 | 
						|
# --==--==--==--==--==--==--==--==--==--==-- #
 | 
						|
proc get_joplin_cli_token*(): string =
 | 
						|
  var flagName: string = ""
 | 
						|
  var flagValue: string = ""
 | 
						|
  var result = execCmdEx("joplin config api.token")
 | 
						|
 | 
						|
  if result.exitCode == 0:
 | 
						|
      let param1 = result.output
 | 
						|
      let flagSplit = param1.split(" = ")
 | 
						|
      flagName = flagSplit[0]
 | 
						|
      flagValue = flagSplit[1]
 | 
						|
  
 | 
						|
  return flagValue
 | 
						|
 | 
						|
 | 
						|
# --==--==--==--==--==--==--==--==--==--==-- #
 | 
						|
# PROC : start Joplin Terminal
 | 
						|
# --==--==--==--==--==--==--==--==--==--==-- #
 | 
						|
proc joplin_cli_start*(): bool =
 | 
						|
  var rc = false
 | 
						|
  var result = execCmdEx("joplin server start &")
 | 
						|
 | 
						|
  if result.exitCode == 0:
 | 
						|
      # echo result.output
 | 
						|
      rc = true
 | 
						|
  else:
 | 
						|
      rc = false   
 | 
						|
  return rc
 | 
						|
 | 
						|
 | 
						|
# --==--==--==--==--==--==--==--==--==--==-- #
 | 
						|
# PROC : check Joplin Terminal staus
 | 
						|
# --==--==--==--==--==--==--==--==--==--==-- #
 | 
						|
proc joplin_cli_status*(): bool =
 | 
						|
  var rc = false
 | 
						|
  var result = execCmdEx("joplin server status")
 | 
						|
 | 
						|
  if result.exitCode == 0:
 | 
						|
      # echo result.output
 | 
						|
      rc = true
 | 
						|
  else:
 | 
						|
      rc = false   
 | 
						|
  return rc
 | 
						|
 | 
						|
 | 
						|
# --==--==--==--==--==--==--==--==--==--==-- #
 | 
						|
# PROC : stop Joplin Terminal
 | 
						|
# --==--==--==--==--==--==--==--==--==--==-- #
 | 
						|
proc joplin_cli_stop*(): bool =
 | 
						|
  var rc = false
 | 
						|
  var result = execCmdEx("joplin server stop")
 | 
						|
 | 
						|
  if result.exitCode == 0:
 | 
						|
      # echo result.output
 | 
						|
      rc = true
 | 
						|
  else:
 | 
						|
      rc = false   
 | 
						|
  return rc
 | 
						|
 | 
						|
 | 
						|
# --==--==--==--==--==--==--==--==--==--==-- #
 | 
						|
# PROC : 
 | 
						|
# --==--==--==--==--==--==--==--==--==--==-- #
 | 
						|
 | 
						|
# proc get_joplin_tags_json*(token:string): Future[] {.async.} =
 | 
						|
 | 
						|
#   # url = fmt"http://localhost:41184/notes/{id}?fields=id,parent_id,title,body,created_time,updated_time,is_conflict,latitude,longitude,altitude,author,source_url,is_todo,todo_due,todo_completed,source,source_application,application_data,order,user_created_time,user_updated_time,encryption_cipher_text,encryption_applied,markup_language,is_shared,share_id,conflict_original_id,master_key_id&token={token}"
 | 
						|
 | 
						|
#   # url = fmt"http://localhost:41184/tags/{id}?fields=id,parent_id,title,created_time,updated_time,user_created_time,user_updated_time,is_shared&token={token}"
 | 
						|
 | 
						|
#   # http://localhost:41184/tags?token=e5f6644fbf6a97ddc55648dae72b11caecda6c6642d8ce0d3b20129b89b196385737eb908923542c3343649ebbf865b55bda031ab4c3a16edc7723ef2ad77d8f
 | 
						|
  
 | 
						|
#   # Variables
 | 
						|
#   var j_tags: joplin_tags
 | 
						|
#   var has_more: bool = true
 | 
						|
#   var page: int = 1
 | 
						|
#   var url: string
 | 
						|
#   var client = newAsyncHttpClient()
 | 
						|
#   var pingCheck: joplin_ping
 | 
						|
#   pingCheck = waitFor ping_joplin(token)
 | 
						|
  
 | 
						|
 | 
						|
#   # check the joplin status befor query 
 | 
						|
#   if pingCheck.ping_status:
 | 
						|
 | 
						|
#     # make sure to check all pages 
 | 
						|
#     while has_more == true:
 | 
						|
      
 | 
						|
#       # request joplin API for notebooks
 | 
						|
#       url = fmt"http://localhost:41184/tags?page={page}&token={token}"
 | 
						|
#       echo("URL tags : ", url)
 | 
						|
#       var json = await client.getContent(url)
 | 
						|
 | 
						|
#       # parse jason
 | 
						|
#       let joplin_tags_Json = parseJson(json)
 | 
						|
 | 
						|
#       # valider qu'il n'y a plus de page 
 | 
						|
#       if not joplin_tags_Json["has_more"].getBool:
 | 
						|
#         has_more = false 
 | 
						|
      
 | 
						|
#       # store json info into an object
 | 
						|
#       var count: int = 1
 | 
						|
#       for nb in joplin_tags_Json["items"]:
 | 
						|
#         echo nb["id"].getstr
 | 
						|
#         echo nb["parent_id"].getstr
 | 
						|
#         echo nb["title"].getstr
 | 
						|
#         count += 1
 | 
						|
      
 | 
						|
#       # aller à la page suivante
 | 
						|
#       page += 1
 | 
						|
  
 | 
						|
 |