Signal management
This commit is contained in:
parent
dfcffeae62
commit
ba2fc5eb73
|
@ -28,7 +28,6 @@ QtObject:
|
|||
self.names.add(chatId)
|
||||
self.endInsertRows()
|
||||
|
||||
|
||||
method rowCount(self: ChatsModel, index: QModelIndex = nil): int =
|
||||
return self.names.len
|
||||
|
||||
|
|
|
@ -8,6 +8,7 @@ import status/utils
|
|||
import status/core as status
|
||||
import status/chat as status_chat
|
||||
import status/test as status_test
|
||||
import status/types as types
|
||||
|
||||
proc mainProc() =
|
||||
# From QT docs:
|
||||
|
@ -18,13 +19,16 @@ proc mainProc() =
|
|||
var app = newQApplication()
|
||||
defer: app.delete() # Defer will run this just before mainProc() function ends
|
||||
|
||||
var appState = state.newAppState()
|
||||
echo appState.title
|
||||
|
||||
var chatsModel = newChatsModel();
|
||||
defer: chatsModel.delete
|
||||
|
||||
var engine = newQQmlApplicationEngine()
|
||||
defer: engine.delete()
|
||||
|
||||
status.init()
|
||||
status.init(appState)
|
||||
|
||||
status_test.setupNewAccount()
|
||||
discard status_test.addPeer("enode://2c8de3cbb27a3d30cbb5b3e003bc722b126f5aef82e2052aaef032ca94e0c7ad219e533ba88c70585ebd802de206693255335b100307645ab5170e88620d2a81@47.244.221.14:443")
|
||||
|
@ -44,8 +48,7 @@ proc mainProc() =
|
|||
let chatsVariant = newQVariant(chatsModel)
|
||||
defer: chatsVariant.delete
|
||||
|
||||
var appState = state.newAppState()
|
||||
echo appState.title
|
||||
|
||||
|
||||
appState.subscribe(proc () =
|
||||
chatsModel.names = @[]
|
||||
|
@ -55,6 +58,7 @@ proc mainProc() =
|
|||
)
|
||||
|
||||
status.startMessenger()
|
||||
|
||||
appState.addChannel("test")
|
||||
appState.addChannel("test2")
|
||||
|
||||
|
@ -62,11 +66,24 @@ proc mainProc() =
|
|||
engine.setRootContextProperty("chatsModel", chatsVariant)
|
||||
|
||||
engine.load("../ui/main.qml")
|
||||
|
||||
# EXAMPLE: this will be triggered once a message is received
|
||||
appState.onSignal(SignalType.Message, proc(myMessage: string): void =
|
||||
echo "I received a message: ", myMessage
|
||||
);
|
||||
|
||||
# Handle signals as part of the state
|
||||
var signalWorker: Thread[AppState]
|
||||
signalWorker.createThread(proc(s:AppState) = s.processSignals, appState)
|
||||
defer: signalWorker.joinThread()
|
||||
|
||||
|
||||
# Qt main event loop is entered here
|
||||
# The termination of the loop will be performed when exit() or quit() is called
|
||||
app.exec()
|
||||
|
||||
|
||||
|
||||
when isMainModule:
|
||||
mainProc()
|
||||
GC_fullcollect()
|
||||
|
|
|
@ -1,2 +1,2 @@
|
|||
--threads:on
|
||||
--tlsEmulation:off
|
||||
--tlsEmulation:off
|
|
@ -1,16 +1,33 @@
|
|||
import status/types
|
||||
import tables
|
||||
|
||||
type Channel = object
|
||||
type
|
||||
ChatChannel = object
|
||||
name*: string
|
||||
type
|
||||
Subscriber* = proc ()
|
||||
|
||||
Subscriber* = proc ()
|
||||
|
||||
SignalSubscriber* = proc(p0: string)
|
||||
|
||||
Signal = object
|
||||
signalType*: SignalType
|
||||
content*: string
|
||||
|
||||
var signalChannel: Channel[Signal]
|
||||
|
||||
type AppState* = ref object
|
||||
title*: string
|
||||
channels*: seq[Channel]
|
||||
subscribers*: seq[Subscriber]
|
||||
title*: string
|
||||
channels*: seq[ChatChannel]
|
||||
subscribers*: seq[Subscriber]
|
||||
signalSubscribers*: Table[SignalType, seq[SignalSubscriber]]
|
||||
|
||||
|
||||
proc newAppState*(): AppState =
|
||||
result = AppState(title: "hello")
|
||||
result = AppState(
|
||||
title: "hello",
|
||||
signalSubscribers: initTable[SignalType, seq[SignalSubscriber]]()
|
||||
)
|
||||
signalChannel.open()
|
||||
|
||||
proc subscribe*(self: AppState, subscriber: Subscriber) =
|
||||
self.subscribers.add(subscriber)
|
||||
|
@ -20,5 +37,37 @@ proc dispatch*(self: AppState) =
|
|||
subscriber()
|
||||
|
||||
proc addChannel*(self: AppState, name: string) =
|
||||
self.channels.add(Channel(name: name))
|
||||
self.channels.add(ChatChannel(name: name))
|
||||
self.dispatch()
|
||||
|
||||
#####################
|
||||
# Signal Handling
|
||||
|
||||
proc processSignals*(self: AppState) =
|
||||
## Polls the signal channel and push the message to each subscriber
|
||||
{.gcsafe.}:
|
||||
while(true):
|
||||
let tried = signalChannel.tryRecv()
|
||||
if tried.dataAvailable and self.signalSubscribers.hasKey(tried.msg.signalType):
|
||||
for subscriber in self.signalSubscribers[tried.msg.signalType]:
|
||||
subscriber(tried.msg.content)
|
||||
defer:
|
||||
signalChannel.close()
|
||||
|
||||
proc addToChannel(s: Signal) {.thread.} =
|
||||
signalChannel.send(s)
|
||||
|
||||
proc nextSignal*(self: AppState, signalType: SignalType, jsonMessage: string) =
|
||||
## This is called by the signal handler for each signal received and
|
||||
## adds it to the signal channel for being consumed by the SignalSubscribers
|
||||
let signal: Signal = Signal(signalType: signalType, content: jsonMessage)
|
||||
var worker: Thread[Signal]
|
||||
createThread(worker, addToChannel, signal)
|
||||
worker.joinThread()
|
||||
|
||||
proc onSignal*(self: AppState, signalType: SignalType, subscriber: SignalSubscriber) =
|
||||
## Register a callback that will be executed once
|
||||
## a signal is received from status-go
|
||||
if not self.signalSubscribers.hasKey(signalType):
|
||||
self.signalSubscribers[signalType] = @[]
|
||||
self.signalSubscribers[signalType].add(subscriber)
|
|
@ -2,12 +2,13 @@ import libstatus
|
|||
import signals
|
||||
import types
|
||||
import chat
|
||||
import "../state"
|
||||
|
||||
proc setSignalHandler(signalHandler: SignalCallback) =
|
||||
libstatus.setSignalEventCallback(signalHandler)
|
||||
|
||||
proc init*() =
|
||||
setSignalHandler(onSignal)
|
||||
proc init*(state: AppState) =
|
||||
setSignalHandler(onSignal(state))
|
||||
|
||||
proc startMessenger*() =
|
||||
chat.startMessenger()
|
||||
|
|
|
@ -1,19 +1,19 @@
|
|||
import types
|
||||
import json
|
||||
import "../state" as state
|
||||
|
||||
var onSignal*: SignalCallback = proc(p0: cstring): void =
|
||||
setupForeignThreadGc()
|
||||
# TODO: Dispatch depending on message type $jsonSignal["type"].getStr
|
||||
# Consider also have an intermediate object with an enum for type
|
||||
# So you do not have to deal with json objects but with a nim type
|
||||
proc onSignal*(state: AppState): SignalCallback =
|
||||
result = proc(p0: cstring): void =
|
||||
setupForeignThreadGc()
|
||||
let jsonSignal = ($p0).parseJson
|
||||
let signalType = $jsonSignal["type"].getStr
|
||||
|
||||
let jsonSignal = ($p0).parseJson
|
||||
let messageType = $jsonSignal["type"].getStr
|
||||
case signalType:
|
||||
of "messages.new":
|
||||
state.nextSignal(SignalType.Message, $jsonSignal)
|
||||
else:
|
||||
state.nextSignal(SignalType.Unknown, $jsonSignal)
|
||||
|
||||
case messageType:
|
||||
of "messages.new":
|
||||
echo $p0
|
||||
else:
|
||||
discard messageType #TODO: do something
|
||||
|
||||
tearDownForeignThreadGc()
|
||||
tearDownForeignThreadGc()
|
||||
|
||||
|
|
|
@ -1 +1,10 @@
|
|||
import hashes
|
||||
|
||||
type SignalCallback* = proc(eventMessage: cstring): void
|
||||
|
||||
type SignalType* {.pure.} = enum
|
||||
Message = "messages.new"
|
||||
Wallet = "wallet"
|
||||
NodeStarted = "node.started"
|
||||
Unknown
|
||||
#TODO: add missing types
|
||||
|
|
Loading…
Reference in New Issue