shell.ml 7.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253
  1. (*
  2. * _ _ ____ _
  3. * _| || |_/ ___| ___ _ __ _ __ ___ | |
  4. * |_ .. _\___ \ / _ \ '_ \| '_ \ / _ \| |
  5. * |_ _|___) | __/ |_) | |_) | (_) |_|
  6. * |_||_| |____/ \___| .__/| .__/ \___/(_)
  7. * |_| |_|
  8. *
  9. * Personal Social Web.
  10. *
  11. * shell.ml
  12. *
  13. * Copyright (C) The #Seppo contributors. All rights reserved.
  14. *
  15. * This program is free software: you can redistribute it and/or modify
  16. * it under the terms of the GNU General Public License as published by
  17. * the Free Software Foundation, either version 3 of the License, or
  18. * (at your option) any later version.
  19. *
  20. * This program is distributed in the hope that it will be useful,
  21. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  22. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  23. * GNU General Public License for more details.
  24. *
  25. * You should have received a copy of the GNU General Public License
  26. * along with this program. If not, see <http://www.gnu.org/licenses/>.
  27. *)
  28. open Seppo_lib
  29. open Astring
  30. (* https://caml.inria.fr/pub/docs/manual-ocaml/libref/Sys.html *)
  31. let ( >>= ) = Result.bind
  32. let ( let* ) = Result.bind
  33. let err i msgs =
  34. let exe = Filename.basename Sys.executable_name in
  35. msgs |> List.cons exe |> String.concat ~sep:": " |> prerr_endline;
  36. i
  37. let exec (args : string list) =
  38. let print_version oc =
  39. let exe = Filename.basename Sys.executable_name in
  40. Printf.fprintf oc "%s: https://Seppo.Social/v/%s+%s\n" exe Version.dune_project_version Version.git_sha;
  41. 0
  42. and print_help oc =
  43. let _exe = Filename.basename Sys.executable_name in
  44. Printf.fprintf oc
  45. {|Some basic tasks on Seppo.Social installations.
  46. If run from commandline:
  47. OPTIONS
  48. --help, -h
  49. print this help
  50. --version, -V
  51. print version
  52. COMMANDS
  53. abs2id
  54. make absolute urls relative to base
  55. ids
  56. dump ids
  57. id2page
  58. look up page indexes for ids
  59. page2s
  60. look up posts for page indexes
  61. s2atom
  62. turn posts to an atom feed
  63. make <files>
  64. refresh if necessary
  65. doap
  66. show 'description of a project'
  67. dot
  68. print file dependencies
  69. note < msg
  70. post a message
  71. |};
  72. (*
  73. "\n\
  74. \ info\n\
  75. \ tell more about this instance\n\n\
  76. \ key-rotate\n\
  77. \ generate new keys\n\n\
  78. \ make\n\
  79. \ 'make' file dependencies\n\n\
  80. \ tag sift\n\
  81. \ filter stdin to stdout\n\n\
  82. \ activitypub\n\
  83. \ make activitypub/index.json\n\n"; *)
  84. 0
  85. and oc = stdout in
  86. let tail s = function
  87. | Error e ->
  88. Logr.err (fun m -> m "%s '%s': %s" E.e1004 s e);
  89. 1
  90. | Ok _ ->
  91. Logr.info (fun m -> m "%s." s);
  92. 0
  93. in
  94. let rz = Ap.Followers.Atom.rule
  95. :: Ap.Followers.Json.rule
  96. :: Ap.Following.Subscribed_to.Atom.rule
  97. :: Ap.Following.Subscribed_to.Json.rule
  98. :: Ap.Person.rule
  99. :: Ap.PersonX.rule
  100. :: Ap.PubKeyPem.pk_rule
  101. :: Ap.PubKeyPem.rule
  102. :: Main.Note.Atom.rule
  103. :: Webfinger.rule
  104. :: Webfinger.Server.rule
  105. :: [] in
  106. match args with
  107. | [ _; "-h" ] | [ _; "--help" ] -> print_help oc
  108. | [ _; "-V" ] | [ _; "--version" ] -> print_version oc
  109. | [ a0; "abs2id" ] ->
  110. a0 |> Filename.dirname |> Unix.chdir;
  111. (match Cfg.Base.(from_file fn) with
  112. | Error _e ->
  113. Logr.err (fun m -> m "can't happen");
  114. 1
  115. | Ok base ->
  116. File.fold_lines (fun init li ->
  117. let u = li
  118. |> Uri.of_string
  119. |> Http.abs_to_rel ~base in
  120. Format.printf "%a\n" Uri.pp u;
  121. init) 0 stdin )
  122. | [ a0; "ids" ] ->
  123. a0 |> Filename.dirname |> Unix.chdir;
  124. Mapcdb.fold_left (fun init (id,_) ->
  125. print_bytes id;
  126. print_newline ();
  127. init) 0 Storage.fn_id_cdb
  128. | [ a0; "id2page" ] ->
  129. a0 |> Filename.dirname |> Unix.chdir;
  130. File.fold_lines (fun init li ->
  131. match li
  132. |> Uri.of_string
  133. |> Storage.TwoPad10.from_id with
  134. | Error e ->
  135. prerr_string e;
  136. init
  137. | Ok ix ->
  138. ix
  139. |> Storage.TwoPad10.to_string
  140. |> print_string;
  141. init) 0 stdin
  142. | [ a0; "page2s" ] ->
  143. a0 |> Filename.dirname |> Unix.chdir;
  144. (match stdin |> Csexp.input_many with
  145. | Error e -> prerr_string e;
  146. 1
  147. | Ok sx ->
  148. let l = sx
  149. |> List.rev
  150. |> Storage.TwoPad10.decode_many in
  151. Storage.fn |> File.in_channel
  152. (fun ic ->
  153. List.fold_left (fun init (p0,p1) ->
  154. seek_in ic p0;
  155. really_input_string ic (p1-p0)
  156. |> print_string;
  157. init)
  158. 0
  159. l ) )
  160. | [ a0; "s2atom" ] ->
  161. a0 |> Filename.dirname |> Unix.chdir;
  162. (match Cfg.Base.(from_file fn) with
  163. | Error e ->
  164. Logr.err (fun m -> m "can't happen: %s" e);
  165. 1
  166. | Ok base ->
  167. match stdin |> Csexp.input_many with
  168. | Error e -> prerr_string e;
  169. 1
  170. | Ok sx ->
  171. let fxo x = Xmlm.output_doc_tree
  172. (fun x -> x)
  173. (Xmlm.make_output ~decl:false (`Channel stdout))
  174. (None,x) in
  175. `El (((Xml.ns_a,"feed"),[
  176. ((Xmlm.ns_xmlns,"xmlns"),Xml.ns_a);
  177. ((Xmlm.ns_xmlns,"wf"),Xml.ns_rfc7033);
  178. (* ((Xmlm.ns_xml,"lang"),lang); *)
  179. ((Xmlm.ns_xml,"base"),base |> Uri.to_string);
  180. ]),
  181. List.fold_left (fun init sx ->
  182. match sx |> Rfc4287.Entry.decode with
  183. | Error e -> Printf.eprintf "error: %s\n" e;
  184. init
  185. | Ok e ->
  186. (e |> Rfc4287.Entry.to_atom ~base)
  187. :: init )
  188. [] sx )
  189. |> fxo;
  190. 0 )
  191. | _ :: ("make" as cmd) :: files ->
  192. Logr.info (fun m -> m "%s %s" cmd (String.concat ~sep:" " files));
  193. files
  194. |> List.fold_left
  195. (fun a fn -> Result.bind a (fun _ -> Make.M2.make rz fn) )
  196. (Ok "")
  197. |> tail cmd
  198. | [ _; "doap" ] ->
  199. (match "doap.rdf" |> Res.read with
  200. | Some v -> Printf.fprintf oc "%s" v
  201. | None -> ());
  202. 0
  203. | [ _b; "note" ] ->
  204. (let* base,profile,author = Main.Note.load_basics () in
  205. let* pk = Ap.PubKeyPem.(private_of_pem pk_pem) in
  206. let* _ =
  207. stdin
  208. |> Rfc4287.Entry.from_channel ~author ~lang:profile.language ~tz:profile.timezone
  209. >>= Main.sift_urls
  210. >>= Main.sift_tags Tag.cdb
  211. >>= Main.sift_handles
  212. >>= Main.Note.publish ~base ~profile ~author
  213. >>= Main.Note.Create.notify_subscribers ~base in
  214. Lwt_main.run (Main.Queue.process_new_and_due ~base ~pk Job.qn)
  215. ) |> tail "note"
  216. | [ _; "info" ] ->
  217. 0
  218. (*
  219. | [ _; "append" ] -> (
  220. let now = (Ptime_clock.now (), Ptime_clock.current_tz_offset_s ()) in
  221. match Txt.of_channel now [] stdin with
  222. | Ok e -> (
  223. match Sepp0.append e with Ok _ -> 0 | Error s -> err 4 [ s ])
  224. | Error _ -> err 5 [ "ouch 300" ])
  225. *)
  226. | [ _; "dot" ] ->
  227. ( match Make.dot oc rz with
  228. | Error _ -> 1
  229. | Ok _ -> 0)
  230. | [ _; "tag"; "sift" ] -> (
  231. match Tag.sift_channel stdin with
  232. | Error _ -> 1
  233. | Ok l ->
  234. l |> List.iter (fun (Tag.Tag s) -> Printf.printf "%s\n" s);
  235. 0)
  236. | [ _; "activitypub" as cmd ] -> (
  237. Make.make rz Ap.Person.target
  238. |> tail cmd
  239. )
  240. | _ -> err 2 [ "get help with -h" ]