Facebook
From Phil, 5 Months ago, written in Nimrod.
Embed
Download Paste or View Raw
Hits: 166
  1.  
  2. import owlkettle, owlkettle/[widgetutils, adw]
  3. import owlkettle/bindings/gtk
  4. import std/[options, os]
  5.  
  6. var counter: int = 0
  7.  
  8. ## Communication
  9.  
  10. type ChannelHub = ref object
  11.   serverChannel: Channel[string]
  12.   clientChannel: Channel[string]
  13.  
  14. proc sendToServer(hub: ChannelHub, msg: string): bool =
  15.   echo "send client => server: ", msg
  16.   hub.clientChannel.trySend(msg)
  17.  
  18. proc sendToClient(hub: ChannelHub, msg: string): bool =
  19.   echo "send client <= server: ", msg
  20.   hub.serverChannel.trySend(msg)
  21.  
  22. proc readClientMsg(hub: ChannelHub): Option[string] =
  23.   let response: tuple[dataAvailable: bool, msg: string] = hub.clientChannel.tryRecv()
  24.  
  25.   return if response.dataAvailable:
  26.       echo "read client => server: ", response.repr
  27.       some(response.msg)
  28.     else:
  29.       none(string)
  30.  
  31. proc readServerMsg(hub: ChannelHub): Option[string] =
  32.   let response: tuple[dataAvailable: bool, msg: string] = hub.serverChannel.tryRecv()
  33.  
  34.   result = if response.dataAvailable:
  35.       echo "read client <= server: ", response.repr
  36.       some(response.msg)
  37.     else:
  38.       none(string)
  39.   sleep(0)
  40.  
  41. proc hasServerMsg(hub: ChannelHub): bool =
  42.   hub.serverChannel.peek() > 0
  43.  
  44. ## Server
  45.  
  46. proc setupServer(channels: ChannelHub): Thread[ChannelHub] =
  47.   proc serverLoop(hub: ChannelHub) =
  48.     while true:
  49.       let msg = hub.readClientMsg()
  50.       if msg.isSome():
  51.         discard hub.sendToClient("Received Message " & $counter)
  52.  
  53.         counter.inc
  54.       sleep(0) # Reduces stress on CPU when idle, increase when higher latency is acceptable for even better idle efficiency
  55.  
  56.   createThread(result, serverLoop, channels)
  57.  
  58. ## Client
  59.  
  60. proc addServerListener(app: Viewable, hub: ChannelHub, priority: int = 200) # Forward declaration
  61.  
  62. viewable App:
  63.   hub: ChannelHub
  64.   backendMsg: string = ""
  65.  
  66.   hooks:
  67.     afterBuild:
  68.       addServerListener(state, state.hub)
  69.  
  70. type ListenerData = object
  71.   hub: ChannelHub
  72.   app: Viewable
  73.  
  74. proc addServerListener(app: Viewable, hub: ChannelHub, priority: int = 200) =
  75.   echo "Setup Server Listener"
  76.   proc serverMessageListener(data: pointer): cbool {.cdecl.} =
  77.     let cell = cast[ptr ListenerData](data)
  78.     let listenerData = cell[]
  79.    
  80.     if listenerData.hub.hasServerMsg():
  81.       discard listenerData.app.redraw()
  82.  
  83.     return true.cbool
  84.  
  85.   let data = allocSharedCell(ListenerData(hub: hub, app: app))
  86.   discard g_idle_add_full(cint(priority), serverMessageListener, data, nil)
  87.  
  88. method view(app: AppState): Widget =
  89.   let msg: Option[string] = app.hub.readServerMsg()
  90.   if msg.isSome():
  91.     app.backendMsg = msg.get()
  92.    
  93.   result = gui:
  94.     Window:
  95.       defaultSize = (500, 150)
  96.       title = "Client Server Example"
  97.      
  98.       Box:
  99.         orient = OrientY
  100.         margin = 12
  101.         spacing = 6
  102.        
  103.         Button {.hAlign: AlignCenter, vAlign: AlignCenter.}:
  104.           Label(text = "Click me")
  105.          
  106.           proc clicked() =
  107.             discard app.hub.sendToServer("Frontend message!")
  108.            
  109.  
  110.         Label(text = "Message sent by Backend: ")
  111.         Label(text = app.backendMsg)
  112.  
  113. proc setupClient(channels: ChannelHub): Thread[ChannelHub] =
  114.   proc startOwlkettle(hub: ChannelHub) =
  115.     adw.brew(gui(App(hub = hub)))
  116.  
  117.   createThread(result, startOwlkettle, channels)
  118.  
  119.  
  120. proc main() =
  121.   var serverToClientChannel: Channel[string]
  122.   var clientToServerChannel: Channel[string]
  123.   serverToClientChannel.open()
  124.   clientToServerChannel.open()
  125.  
  126.   let hub = ChannelHub(serverChannel: serverToClientChannel, clientChannel: clientToServerChannel)
  127.  
  128.   let client = setupClient(hub)
  129.   let server = setupServer(hub)
  130.   joinThreads(server, client)
  131.  
  132. main()