lol took me forever to understand lwt but finally have concurrency in the actor event processing handlers

This commit is contained in:
cqc
2021-10-07 14:07:26 -05:00
parent c8e9e1bd6c
commit 630ccb0a6f
7 changed files with 256 additions and 332 deletions

9
dune
View File

@ -2,11 +2,10 @@
(dev (dev
(flags (:standard -warn-error -A)))) (flags (:standard -warn-error -A))))
(executable (library
(name main) (name human)
(modes byte) (modes byte)
(modules main) (modules human)
(link_flags (-linkall))
(libraries (libraries
topinf topinf
lwt_ppx lwt_ppx
@ -26,6 +25,8 @@
(modes byte) (modes byte)
(modules irc) (modules irc)
(libraries (libraries
human
lwt
fmt fmt
topinf topinf
lwt_ppx lwt_ppx

View File

@ -22,8 +22,6 @@ module F = Fmt
module Input = struct module Input = struct
open CamomileLibrary open CamomileLibrary
open Zed_edit
open CamomileLibrary
(** Type of key code. *) (** Type of key code. *)
type code = type code =
@ -226,7 +224,6 @@ end
module Event = struct module Event = struct
open Tsdl open Tsdl
open CamomileLibrary open CamomileLibrary
open Zed_edit
open Input open Input
type mouse = int * int type mouse = int * int
@ -393,8 +390,6 @@ module Display = struct
open Tgles2 open Tgles2
open Tsdl open Tsdl
open Gg open Gg
open CamomileLibrary
open Zed_edit
open Wall open Wall
module I = Image module I = Image
module P = Path module P = Path
@ -418,6 +413,7 @@ module Display = struct
(the Wall.image extents) *) (the Wall.image extents) *)
type image = box2 * Wall.image type image = box2 * Wall.image
type pane = state -> state * image type pane = state -> state * image
type actor = (Event.events -> pane Lwt.t) ref
let pane_empty s = let pane_empty s =
(s, (Box2.of_pts (Box2.o s.box) (Box2.o s.box), Image.empty)) (s, (Box2.of_pts (Box2.o s.box) (Box2.o s.box), Image.empty))
@ -505,7 +501,7 @@ module Display = struct
Sdl.gl_swap_window frame.sdl_win ; Sdl.gl_swap_window frame.sdl_win ;
Ok () Ok ()
let display_frame frame actor = let display_frame frame (actor : actor) =
(* create and fill event list *) (* create and fill event list *)
let convert_event ev = let convert_event ev =
match Event.event_of_sdlevent ev with match Event.event_of_sdlevent ev with
@ -519,18 +515,25 @@ module Display = struct
events := !events @ [convert_event ev] events := !events @ [convert_event ev]
done ) ; done ) ;
handle_frame_events frame !events ; handle_frame_events frame !events ;
if List.length !events > 0 then if List.length !events > 0 then (
(* recompute the actor definition with the new events to return a new pane *) (* recompute the actor definition with the new events to return a new pane *)
frame.last_pane <- actor !events ; !actor !events
>>= fun p ->
frame.last_pane <- p ;
(* call draw_pane because we should redraw now that we have updated *) (* call draw_pane because we should redraw now that we have updated *)
draw_pane frame frame.last_pane ignore (draw_pane frame frame.last_pane) ;
Lwt.return_unit )
else Lwt.return_unit
let run frame render () = let run frame actor () =
let frame = get_result frame in let frame = get_result frame in
Sdl.show_window frame.sdl_win ; Sdl.show_window frame.sdl_win ;
while not frame.quit do let rec loop () =
ignore (display_frame frame render) ignore (display_frame frame actor) ;
done ; Lwt_main.yield ()
>>= fun () ->
if not frame.quit then loop () else Lwt.return_unit in
Lwt_main.run (loop ()) ;
print_endline "quit" ; print_endline "quit" ;
Sdl.hide_window frame.sdl_win ; Sdl.hide_window frame.sdl_win ;
Sdl.gl_delete_context frame.gl ; Sdl.gl_delete_context frame.gl ;
@ -660,32 +663,27 @@ end
module Panel = struct module Panel = struct
open Display open Display
open Wall
open Gg open Gg
type t = type t =
{ mutable act: t -> Event.events -> t * Display.pane { mutable act: t -> Event.events -> (t * Display.pane) Lwt.t
; mutable subpanels: t list ; mutable subpanels: t list
; mutable tag: string } ; mutable tag: string }
type actor = Event.events -> Display.pane
let blank = let blank =
{ act= (fun panel _events -> (panel, Display.pane_empty)) { act=
(fun panel _events -> Lwt.return (panel, Display.pane_empty))
; subpanels= [] ; subpanels= []
; tag= "blank pane" } ; tag= "blank pane" }
let draw (pane : Display.pane) = let draw (pane : Display.pane) =
{ act= (fun panel _events -> (panel, pane)) { act= (fun panel _events -> Lwt.return (panel, pane))
; subpanels= [] ; subpanels= []
; tag= "draw-pane" } ; tag= "draw-pane" }
let actor (panel : t) : Event.events -> Display.pane = let actor (panel : t) : Event.events -> Display.pane Lwt.t =
let enclosure = ref panel in
fun events -> fun events ->
let panel, pane = panel.act !enclosure events in panel.act panel events >>= fun (_panel, pane) -> Lwt.return pane
enclosure := panel ;
pane
let filter_events ef p = let filter_events ef p =
{p with act= (fun panel events -> p.act panel (ef events))} {p with act= (fun panel events -> p.act panel (ef events))}
@ -694,12 +692,13 @@ module Panel = struct
let vbox subpanels = let vbox subpanels =
{ act= { act=
(fun panel events -> (fun panel events ->
( panel Lwt_list.map_p
, pane_box Box2.tl_pt (fun subpanel ->
subpanel.act subpanel events
>>= fun (_panel, pane) -> Lwt.return pane )
panel.subpanels
>>= fun pl -> Lwt.return (panel, pane_box Box2.tl_pt pl) )
(* tl_pt is actually bl_pt in the Wall coordinate system *) (* tl_pt is actually bl_pt in the Wall coordinate system *)
(List.map
(fun subpanel -> snd (subpanel.act subpanel events))
panel.subpanels ) ) )
; subpanels ; subpanels
; tag= "vertical-box" } ; tag= "vertical-box" }
@ -707,12 +706,13 @@ module Panel = struct
let hbox subpanels = let hbox subpanels =
{ act= { act=
(fun panel events -> (fun panel events ->
( panel Lwt_list.map_p
, pane_box Box2.br_pt (fun subpanel ->
subpanel.act subpanel events
>>= fun (_panel, pane) -> Lwt.return pane )
panel.subpanels
>>= fun pl -> Lwt.return (panel, pane_box Box2.br_pt pl) )
(* br_pt is actually tr_pt in the Wall coordinate system *) (* br_pt is actually tr_pt in the Wall coordinate system *)
(List.map
(fun subpanel -> snd (subpanel.act subpanel events))
panel.subpanels ) ) )
; subpanels ; subpanels
; tag= "horizontal-box" } ; tag= "horizontal-box" }
@ -720,11 +720,12 @@ module Panel = struct
let obox subpanels = let obox subpanels =
{ act= { act=
(fun panel events -> (fun panel events ->
( panel Lwt_list.map_p
, pane_box Box2.o (fun subpanel ->
(List.map subpanel.act subpanel events
(fun subpanel -> snd (subpanel.act subpanel events)) >>= fun (_panel, pane) -> Lwt.return pane )
panel.subpanels ) ) ) panel.subpanels
>>= fun pl -> Lwt.return (panel, pane_box Box2.o pl) )
; subpanels ; subpanels
; tag= "origin-box" } ; tag= "origin-box" }
@ -843,10 +844,12 @@ module Panel = struct
; out_spaces= ; out_spaces=
(fun n -> add_symbolic_output_item sob (Output_spaces n)) } (fun n -> add_symbolic_output_item sob (Output_spaces n)) }
let prettyprint ?(height = !g_text_height) fpp = let prettyprint ?(height = !g_text_height) ?(tag = "pretty-print")
{ act= (fun panel _events -> (panel, draw_pp height fpp)) fpp =
{ act=
(fun panel _events -> Lwt.return (panel, draw_pp height fpp))
; subpanels= [] ; subpanels= []
; tag= "pretty-print" } ; tag }
module Textedit = struct module Textedit = struct
let bindings = let bindings =
@ -963,14 +966,13 @@ module Panel = struct
Format.pp_open_hvbox pp 0 ; Format.pp_open_hvbox pp 0 ;
F.text pp before_cursor ; F.text pp before_cursor ;
Format.pp_open_stag pp Format.pp_open_stag pp
Display.( (Cursor (Wall.Color.v 0.99 0.99 0.125 0.3)) ;
Cursor (Wall.Color.v 0.99 0.99 0.125 0.3)) ;
F.pf pp "" ; F.pf pp "" ;
Format.pp_close_stag pp () ; Format.pp_close_stag pp () ;
F.text pp after_cursor ; F.text pp after_cursor ;
F.pf pp "@." ; F.pf pp "@." ;
Format.pp_close_box pp () ) in Format.pp_close_box pp () ) in
(panel, draw_textedit) ) Lwt.return (panel, draw_textedit) )
; subpanels= [] ; subpanels= []
; tag= "textedit" } ; tag= "textedit" }
@ -979,12 +981,14 @@ module Panel = struct
= =
{ act= { act=
(fun panel _events -> (fun panel _events ->
Lwt.return
( panel ( panel
, draw_pp height (fun pp -> , draw_pp height (fun pp ->
Format.pp_open_hbox pp () ; Format.pp_open_hbox pp () ;
F.text pp F.text pp
(List.fold_left (List.fold_left
(fun s x -> Input.to_string_compact x ^ " " ^ s) (fun s x ->
Input.to_string_compact x ^ " " ^ s )
"" b.last_keyseq ) ; "" b.last_keyseq ) ;
F.text pp "-> " ; F.text pp "-> " ;
F.text pp F.text pp
@ -996,7 +1000,8 @@ module Panel = struct
s s
^ Input.Bind.( ^ Input.Bind.(
match x with match x with
| Zed a -> Zed_edit.name_of_action a | Zed a ->
Zed_edit.name_of_action a
| Custom _ -> "Custom") | Custom _ -> "Custom")
^ "; " ) ^ "; " )
a "" a ""
@ -1038,7 +1043,7 @@ module Panel = struct
| Some text -> | Some text ->
Textedit.insert me.te text ; Textedit.insert me.te text ;
(hbox panel.subpanels).act panel events (hbox panel.subpanels).act panel events
| None -> (panel, Display.pane_empty) | None -> Lwt.return (panel, Display.pane_empty)
(* don't draw anything if modal isn't active *) ) (* don't draw anything if modal isn't active *) )
; subpanels= ; subpanels=
[ prettyprint (fun pp -> F.text pp me.prompt) [ prettyprint (fun pp -> F.text pp me.prompt)
@ -1063,8 +1068,8 @@ module Toplevel = struct
let init () = let init () =
let sob = Format.make_symbolic_output_buffer () in let sob = Format.make_symbolic_output_buffer () in
let ppf = Format.formatter_of_symbolic_output_buffer sob in Topinf.ppf := Format.formatter_of_symbolic_output_buffer sob ;
{eval= Topinf.init ppf; res= sob} {eval= !Topinf.eval; res= sob}
let eval t str = let eval t str =
let ppf = Format.formatter_of_symbolic_output_buffer t.res in let ppf = Format.formatter_of_symbolic_output_buffer t.res in
@ -1094,7 +1099,8 @@ module Store = struct
{ store: Istore.t { store: Istore.t
; mutable view: Istore.key ; mutable view: Istore.key
; mutable selection: Istore.key ; mutable selection: Istore.key
; mutable editmode: bool } ; mutable editmode: bool
; sob: Format.symbolic_output_buffer }
let make_storeview ?(path = []) storepath branch = let make_storeview ?(path = []) storepath branch =
Lwt_main.run Lwt_main.run
@ -1109,7 +1115,8 @@ module Store = struct
{ store { store
; view ; view
; selection= Istore.Key.v [fst (List.hd viewlist)] ; selection= Istore.Key.v [fst (List.hd viewlist)]
; editmode= false } ) ; editmode= false
; sob= Format.make_symbolic_output_buffer () } )
let directives (top : Toplevel.t) sv = let directives (top : Toplevel.t) sv =
let dir_use_key key_lid = let dir_use_key key_lid =
@ -1223,10 +1230,44 @@ module Store = struct
>>= function >>= function
| Some `Node -> Lwt.return_true | _ -> Lwt.return_false ) | Some `Node -> Lwt.return_true | _ -> Lwt.return_false )
in in
let update_storeview () =
ignore (Format.flush_symbolic_output_buffer sv.sob) ;
let pp = Format.formatter_of_symbolic_output_buffer sv.sob in
let rec draw_levels ?(indent = 0) (sel : Istore.key)
(tree : Istore.tree) : unit Lwt.t =
Istore.Tree.list tree []
>>= Lwt_list.iteri_s (fun _i (step, node) ->
Format.pp_open_box pp indent ;
if sel = [step] then (
Format.pp_open_stag pp
(Panel.Cursor (Wall.Color.v 0.99 0.99 0.125 0.3)) ;
F.pf pp "@," ;
Format.pp_close_stag pp () ) ;
Istore.Tree.kind node []
>>= fun k ->
( match k with
| Some `Contents ->
F.pf pp "- %s@." step ; Lwt.return_unit
| Some `Node ->
F.pf pp "> %s@." step ;
let subsel =
match Istore.Key.decons sel with
| Some (_tstep, subkey) -> subkey
| None -> [] in
Format.pp_open_vbox pp 0 ;
draw_levels ~indent:(indent + 1) subsel node
>>= fun () ->
Format.pp_close_box pp () ;
Lwt.return_unit
| None -> F.pf pp "ERROR: None" ; Lwt.return_unit )
>>= fun () ->
Format.pp_close_box pp () ;
Lwt.return_unit ) in
Istore.get_tree sv.store sv.view >>= draw_levels sv.selection
in
let update_textedit () = let update_textedit () =
Panel.Textedit.clear te ; Panel.Textedit.clear te ;
Lwt_main.run Istore.get_tree sv.store sv.view
( Istore.get_tree sv.store sv.view
>>= fun t -> >>= fun t ->
Istore.Tree.kind t sv.selection Istore.Tree.kind t sv.selection
>>= function >>= function
@ -1238,7 +1279,7 @@ module Store = struct
| Some `Node -> | Some `Node ->
Panel.Textedit.insert te "Node..." ; Panel.Textedit.insert te "Node..." ;
Lwt.return_unit Lwt.return_unit
| None -> Lwt.return_unit ) in | None -> Lwt.return_unit in
let navbinds = let navbinds =
let open Input.Bind in let open Input.Bind in
let new_contents name content = let new_contents name content =
@ -1260,7 +1301,8 @@ module Store = struct
@@ add [([], Char 's')] [Custom (navigate sv `Next)] @@ add [([], Char 's')] [Custom (navigate sv `Next)]
@@ add [([], Char 'd')] [Custom (navigate sv `Sub)] @@ add [([], Char 'd')] [Custom (navigate sv `Sub)]
@@ add [([], Char 'a')] [Custom (navigate sv `Sup)] @@ add [([], Char 'a')] [Custom (navigate sv `Sup)]
@@ add [([], Char 'e')] @@ add
[([], Char 'e')] (* enter edit mode *)
[ Custom [ Custom
(fun () -> (fun () ->
if not (is_node sv.selection) then if not (is_node sv.selection) then
@ -1305,19 +1347,20 @@ module Store = struct
[([], Char 'x')] (* execute contents/node *) [([], Char 'x')] (* execute contents/node *)
[ Custom [ Custom
(fun () -> (fun () ->
Panel.Modal.start ~prompt:"!!Not implemented!!" Toplevel.eval top (Panel.Textedit.contents te) ) ]
modalstate "" (fun _ -> ()) ) ]
empty in empty in
let bindstate = Input.Bind.init navbinds in let bindstate = Input.Bind.init navbinds in
{ act= { act=
(fun panel events -> (fun panel events ->
if ( if
(not sv.editmode) (not sv.editmode)
&& not (Panel.Modal.is_active modalstate) && not (Panel.Modal.is_active modalstate)
then ( then (
Input.Bind.process bindstate events ; Input.Bind.process bindstate events ;
update_textedit () ) ; Lwt.join [update_storeview (); update_textedit ()] )
(Panel.vbox panel.subpanels).act panel events ) else Lwt.return_unit )
>>= fun () -> (Panel.vbox panel.subpanels).act panel events
)
; subpanels= ; subpanels=
[ Panel.filter_events [ Panel.filter_events
(fun ev -> (fun ev ->
@ -1325,39 +1368,8 @@ module Store = struct
(Panel.Modal.panel modalstate) (Panel.Modal.panel modalstate)
; Panel.hbox ; Panel.hbox
[ Panel.prettyprint (fun pp -> [ Panel.prettyprint (fun pp ->
let rec draw_levels ?(indent = 0) Panel.format_symbolic_output_buffer pp
(tree : Istore.tree) (sel : Istore.key) = (Format.get_symbolic_output_buffer sv.sob) )
List.iteri
(fun _i (step, node) ->
Format.pp_open_box pp indent ;
if sel = [step] then (
Format.pp_open_stag pp
Display.(
Panel.Cursor
(Wall.Color.v 0.99 0.99 0.125 0.3)) ;
F.pf pp "@," ;
Format.pp_close_stag pp () ) ;
( match
Lwt_main.run (Istore.Tree.kind node [])
with
| Some `Contents -> F.pf pp "- %s@." step
| Some `Node ->
F.pf pp "> %s@." step ;
let subsel =
match Istore.Key.decons sel with
| Some (_tstep, subkey) -> subkey
| None -> [] in
Format.pp_open_vbox pp 0 ;
draw_levels ~indent:(indent + 1) node
subsel ;
Format.pp_close_box pp ()
| None -> F.pf pp "ERROR: None" ) ;
Format.pp_close_box pp () )
(Lwt_main.run (Istore.Tree.list tree [])) in
let root =
Lwt_main.run (Istore.get_tree sv.store sv.view)
in
draw_levels root sv.selection )
; Panel.vbox ; Panel.vbox
[ Panel.filter_events [ Panel.filter_events
(fun ev -> if sv.editmode then ev else []) (fun ev -> if sv.editmode then ev else [])
@ -1375,109 +1387,18 @@ module Store = struct
; tag= "store-editor" } ; tag= "store-editor" }
end end
open Wall let std_actor root_panel =
open Gg
module I = Image
module P = Path
module Text = Wall_text
type top =
{ te: Panel.Textedit.t
; res: Format.symbolic_output_buffer
; mutable eval: Topinf.evalenv option
; mutable path: string list
; mutable histpath: string list
; storeview: Store.storeview }
let make_top storepath ?(branch = "current") () =
let t =
{ te= Panel.Textedit.make "" ()
; res= Format.make_symbolic_output_buffer ()
; eval= None
; path= ["init"]
; histpath= ["history"]
; storeview= Store.make_storeview storepath branch } in
Topinf.ppf := Format.formatter_of_symbolic_output_buffer t.res ;
(* Format.pp_set_formatter_out_functions Format.std_formatter
(out_funs_of_sob t.res) ;*)
Panel.Textedit.insert t.te
(Lwt_main.run (Store.Istore.get t.storeview.store t.path)) ;
t
let top_panel (t : top) =
let ppf = Format.formatter_of_symbolic_output_buffer t.res in
Topinf.ppf := ppf ;
let eval =
match t.eval with
(* HACK use Lazy.? *)
| None ->
let e =
match !Topinf.eval with
| Some e -> e
| None -> Topinf.init ppf in
t.eval <- Some e ;
e
| Some e -> e in
let eval () =
try
ignore
(Lwt_main.run
( Store.Istore.tree t.storeview.store
>>= fun tree ->
Store.Istore.Tree.add tree
(t.histpath @ ["input"])
(Panel.Textedit.contents t.te) ) ) ;
ignore (Format.flush_symbolic_output_buffer t.res) ;
eval ppf (Panel.Textedit.contents t.te ^ ";;") ;
(*HACK to prevent getting stuck in parser*)
let b = Buffer.create 69 in
Panel.format_symbolic_output_buffer
(Format.formatter_of_buffer b)
(Format.get_symbolic_output_buffer t.res) ;
ignore
(Lwt_main.run
( Store.Istore.tree t.storeview.store
>>= fun tree ->
Store.Istore.Tree.add tree
(t.histpath @ ["output"])
(Buffer.contents b) ) ) ;
ignore
(Lwt_main.run
(Store.Istore.set_exn t.storeview.store
~info:(Irmin_unix.info "history")
t.path
(Panel.Textedit.contents t.te) ) ) ;
Panel.Textedit.clear t.te
with e ->
F.pf ppf "Exception in pane_top//eval@." ;
Location.report_exception ppf e ;
F.epr "Exception in pane_top//eval@." in
t.te.keybind.bindings <-
Input.(
Bind.add
[([Ctrl], Code Enter)]
Bind.[Custom eval]
t.te.keybind.bindings) ;
Panel.(
vbox
[ Textedit.panel t.te
; prettyprint (fun pp ->
Format.pp_open_hovbox pp 0 ;
format_symbolic_output_buffer pp
(Format.get_symbolic_output_buffer t.res) ;
Format.pp_close_box pp () ;
F.flush pp () ) (*; draw_textedit_input height t.te *) ])
(*let top_1 = make_top "../rootstore" () *)
let () =
let actor =
Panel.actor Panel.actor
(Panel.obox (Panel.obox
[ Panel.draw (fun (s : Display.state) -> [ Panel.draw (fun (s : Display.state) ->
(s, Display.fill_box (Display.gray 0.125) s.box) ) (s, Display.fill_box (Display.gray 0.125) s.box) )
; Store.editor "../rootstore" ] ) in ; root_panel ] )
Display.(run (make_frame ~title:"hi" ~w:1440 ~h:900 ()) actor) ()
let root_actor = ref (std_actor (Store.editor "../rootstore"))
let start () =
Display.(
run (make_frame ~title:"hi" ~w:1440 ~h:900 ()) root_actor ())
(* Implement the "window management" as just toplevel defined functions that manipulate the window tree *) (* Implement the "window management" as just toplevel defined functions that manipulate the window tree *)

View File

@ -6,11 +6,13 @@ let print_directives () =
Format.printf "directive_info_table:@."; Format.printf "directive_info_table:@.";
Hashtbl.iter (fun n _ -> Format.printf "\t%s@." n) Topinf.directive_info_table;; Hashtbl.iter (fun n _ -> Format.printf "\t%s@." n) Topinf.directive_info_table;;
#directory "+compiler-libs";; (*#directory "+compiler-libs";; *)
let print_modules () = let print_modules () =
Format.printf "Env.fold_modules !Topinf.toplevel_env :\n"; Format.printf "Env.fold_modules !Topinf.toplevel_env :\n";
Env.fold_modules (fun modname _ _ () -> Format.printf "\t%s@." modname) None !Topinf.toplevel_env ();; Env.fold_modules (fun modname _ _ () -> Format.printf "\t%s@." modname) None !Topinf.toplevel_env ();;
(*print_modules ();;*)
#use_silently "main.ml";; #use_silently "human.ml";;
start ();;

166
irc.ml
View File

@ -1,109 +1,109 @@
(* (*
when all you can do is type, making things more complicated than a list is hard? when all you can do is type, making things more complicated than a list is hard?
we need to design this somehow before implementing it we need to design this somehow before implementing it
really the graphical drawing / window management funcitons i think at this point. really the graphical drawing / window management funcitons i think at this point.
features: features:
- message drafts? more like, if you send too many messages to someone all at once it will hold them so you can respond later and not flood people....... - message drafts? more like, if you send too many messages to someone all at once it will hold them so you can respond later and not flood people.......
- i mean really what you want is an editable stream, so you can stage messages for later - i mean really what you want is an editable stream, so you can stage messages for later
- because i mean, if this is a bicycle, and you can make it however you want, you can just fuck with the conversation thread with computer assistance instaed of just relying on your memory. - because i mean, if this is a bicycle, and you can make it however you want, you can just fuck with the conversation thread with computer assistance instaed of just relying on your memory.
*) *)
open Lwt open Lwt
module C = Irc_client_tls open Lwt_react
module M = Irc_message module F = Fmt
let host = ref "irc.hackint.org" module Communicator = struct
let port = ref 6697 type msg = {content: string; time: string; mutable seen: bool}
let nick = ref "cqcaml"
let channel = ref "#freeside"
let message = "Hello, world! This is a test from ocaml-irc-client"
let output_channel_of_ppf ppf = let create_msg ?(time = "<ts>") content =
Lwt_io.make ~mode:Output (fun b o l -> {content; time; seen= false}
let s = String.sub (Lwt_bytes.to_string b) o l in
Fmt.pf ppf "%s" s ;
Lwt.return (String.length s) )
let callback connection result = type channel =
match result with { mutable name: string
| Result.Ok ({M.command= M.Other _; _} as msg) -> ; mutable content: msg list
Lwt_io.printf "Got unknown message: %s\n" (M.to_string msg) ; mutable sender: string -> unit }
>>= fun () -> Lwt_io.flush Lwt_io.stdout
| Result.Ok ({M.command= M.PRIVMSG (_target, data); _} as msg) ->
Lwt_io.printf "Got message: %s\n" (M.to_string msg)
>>= fun () ->
Lwt_io.flush Lwt_io.stdout
>>= fun () ->
C.send_privmsg ~connection ~target:"cqc"
~message:("ack: " ^ data)
| Result.Ok msg ->
Lwt_io.printf "Got message: %s\n" (M.to_string msg)
>>= fun () -> Lwt_io.flush Lwt_io.stdout
| Result.Error e -> Lwt_io.printl e
let lwt_main () = let add_msg (c : channel) msg = c.content <- msg :: c.content
type c = {mutable channel: channel; mutable subs: c list}
type protocol = Irc | Email | Rss | Mublog
let make_channel (c : c) ?(sender = fun _ -> ()) name =
c.subs <-
{channel= {name; content= []; sender}; subs= []} :: c.subs
let make () : c =
let c =
{ name= "top"
; content= [create_msg "Wecome to the Communicator"]
; sender= (fun _ -> ()) } in
c.sender <- (fun s -> c.content <- create_msg s :: c.content) ;
c.sender "Currently only IRC is implemented" ;
{channel= c; subs= []}
type connection = unit Lwt.t
module Irc = struct
module C = Irc_client_tls
module M = Irc_message
let connection (c : c) server port nick channels : unit Lwt.t =
let add_msg cn str = add_msg cn.channel (create_msg str) in
C.reconnect_loop ~after:30 C.reconnect_loop ~after:30
~connect:(fun () -> ~connect:(fun () ->
Lwt_io.printl "Connecting..." Lwt_io.printl "Connecting..."
>>= fun () -> >>= fun () -> C.connect_by_name ~server ~port ~nick () )
C.connect_by_name ~server:!host ~port:!port ~nick:!nick () )
~f:(fun connection -> ~f:(fun connection ->
Lwt_io.printl "Connected" Lwt_io.printl "Connected"
>>= fun () -> >>= fun () ->
Lwt_io.printl "send join msg" Lwt_list.iter_p
>>= fun () -> (fun channel ->
C.send_join ~connection ~channel:!channel let joiner = C.send_join ~connection ~channel in
>>= fun () -> (* make_channel c ~sender:(fun s ->
C.send_privmsg ~connection ~target:!channel ~message ) C.send_privmsg ~target:channel ~message:s) channel ; *)
~callback () joiner )
channels )
~callback:(fun _connection result ->
match result with
| Result.Ok ({M.command= M.Other _; _} as msg) ->
add_msg c
(F.str "Got unknown message: %s\n" (M.to_string msg)) ;
Lwt.return_unit
| Result.Ok ({M.command= M.PRIVMSG (target, data); _} as msg)
->
add_msg c
(F.str "Got PRIVMSG: target=%s, data=%s; %s\n" target
data (M.to_string msg) ) ;
Lwt.return_unit
| Result.Ok msg ->
add_msg c (M.to_string msg) ;
Lwt.return_unit
| Result.Error e -> Lwt_io.printl e )
()
end
module Panel = struct
let panel c =
Panel.prettyprint ~height:20. ~tag:"Communicator" (fun pp ->
F.pf pp " <><><> COMMUNICATOR <><><> @.@." ;
List.iter
(fun msg -> F.pf pp "[%s] %s@." msg.time msg.content)
c.channel.content )
end
end
let _ = let _ =
Lwt_main.run let comm = Communicator.make () in
(Lwt.catch lwt_main (fun e -> let hackint =
Printf.printf "exception: %s\n" (Printexc.to_string e) ; Communicator.Irc.connection comm "irc.hackint.org" 6697 "cqcaml"
exit 1 ) ) ["#CQC"] in
root_actor := std_actor (Communicator.Panel.panel comm) ;
Lwt.async (fun () -> hackint)
(* ocamlfind ocamlopt -package irc-client.lwt -linkpkg code.ml *) (**
program starts...
- spawn connections to servers
- these connections will populate the Channel.t in a Channel.tree
(*open Lwt **)
module C = Irc_client_lwt
let host = "irc.hackint.org"
let port = 6697
let realname = "Demo IRC bot"
let nick = "cqcqcqcqc"
let username = nick
let channel = "#freeside"
let message = "Hello, world! This is a test from ocaml-irc-client"
let callback oc _connection result =
let open Irc_message in
match result with
| Result.Ok msg ->
Fmt.epr "irc msg: msg" ;
Lwt_io.fprintf oc "Got message: %s\n" (to_string msg)
| Result.Error e -> Lwt_io.fprintl oc e
let lwt_main =
let oc = output_channel_of_ppf !Topinf.ppf in
Lwt_unix.gethostbyname host
>>= fun he ->
C.connect
~addr:he.Lwt_unix.h_addr_list.(0)
~port ~username ~mode:0 ~realname ~nick ()
>>= fun connection ->
Lwt_io.fprintl oc "Connected"
>>= fun () ->
C.send_join ~connection ~channel
>>= fun () ->
C.send_privmsg ~connection ~target:channel ~message
>>= fun () ->
C.listen ~connection ~callback:(callback oc) ()
>>= fun () -> C.send_quit ~connection ()
let _ = Lwt_main.run lwt_main
*)

View File

View File

@ -44,7 +44,7 @@ let toplevel_value_bindings : Obj.t String.Map.t ref =
ref String.Map.empty ref String.Map.empty
let ppf = ref Format.std_formatter let ppf = ref Format.std_formatter
let eval = ref None let eval = ref (fun _ _ -> ())
let getvalue name = let getvalue name =
try String.Map.find name !toplevel_value_bindings try String.Map.find name !toplevel_value_bindings
@ -2398,5 +2398,5 @@ let init ppf =
Location.input_phrase_buffer := Some phrase_buffer ; Location.input_phrase_buffer := Some phrase_buffer ;
Sys.catch_break true ; Sys.catch_break true ;
run_hooks After_setup ; run_hooks After_setup ;
eval := Some (eval_fun lb) ; eval := eval_fun lb ;
eval_fun lb eval_fun lb

View File

@ -26,5 +26,5 @@ val add_directive :
val directive_info_table : (string, directive_info) Hashtbl.t val directive_info_table : (string, directive_info) Hashtbl.t
val ppf : Format.formatter ref val ppf : Format.formatter ref
val eval : evalenv option ref val eval : evalenv ref
val eval_value_path : Env.t -> Path.t -> Obj.t val eval_value_path : Env.t -> Path.t -> Obj.t