cc-haxe/src/kernel/KernelEvents.hx

360 lines
15 KiB
Haxe

package kernel;
import kernel.turtle.TurtleMutex;
import kernel.turtle.Turtle;
import kernel.peripherals.Peripherals.Peripheral;
import kernel.log.Log;
import lib.Pos;
import cc.HTTP.HTTPResponse;
import lua.TableTools;
import lua.Coroutine;
import haxe.Exception;
using tink.CoreApi;
using lua.Table;
/**
Class for interacting with the native pullEvent system.
**/
class KernelEvents {
/**
Depends on: (Nothing)
**/
public static var onAlarm(default, null):Signal<Int>;
public static var onChar(default, null):Signal<String>;
public static var onDisk(default, null):Signal<String>;
public static var onDiskEject(default, null):Signal<String>;
public static var onHttpCheck(default, null):Signal<{url:String, success:Bool, failReason:Any}>;
public static var onHttpFailure(default, null):Signal<{url:String, failReason:String, handle:HTTPResponse}>;
public static var onHttpSuccess(default, null):Signal<{url:String, handle:HTTPResponse}>;
public static var onKey(default, null):Signal<{keyCode:Int, isHeld:Bool}>;
public static var onKeyUp(default, null):Signal<Int>;
public static var onModemMessage(default, null):Signal<{
addr:String,
channel:Int,
replyChannel:Int,
message:Dynamic,
distance:Null<Float>
}>;
public static var onMonitorResize(default, null):Signal<String>;
public static var onMonitorTouch(default, null):Signal<{addr:String, pos:Pos}>;
public static var onMouseClick(default, null):Signal<{button:ButtonType, pos:Pos}>;
public static var onMouseDrag(default, null):Signal<{button:ButtonType, pos:Pos}>;
public static var onMouseScroll(default, null):Signal<{dir:Int, pos:Pos}>;
public static var onMouseUp(default, null):Signal<{button:ButtonType, pos:Pos}>;
public static var onPaste(default, null):Signal<String>;
public static var onPeripheral(default, null):Signal<String>;
public static var onPeripheralDetach(default, null):Signal<String>;
public static var onRedstone(default, null):Signal<Noise>;
public static var onSpeakerAudioEmpty(default, null):Signal<String>;
public static var onTaskComplete(default, null):Signal<{id:Int, success:Bool, failedReason:String}>;
public static var onTermResize(default, null):Signal<Noise>;
public static var onTerminate(default, null):Signal<Noise>;
public static var onTimer(default, null):Signal<Int>;
public static var onTurtleInventory(default, null):Signal<Noise>;
public static var onWebsocketClose(default, null):Signal<String>;
public static var onWebsocketFailure(default, null):Signal<{url:String, failReason:String}>;
public static var onWebsocketMessage(default, null):Signal<{url:String, message:String, isBinary:Bool}>;
public static var onWebsocketSuccess(default, null):Signal<{url:String, handle:Any}>;
private static final onAlarmTrigger:SignalTrigger<Int> = Signal.trigger();
private static final onCharTrigger:SignalTrigger<String> = Signal.trigger();
private static final onDiskTrigger:SignalTrigger<String> = Signal.trigger();
private static final onDiskEjectTrigger:SignalTrigger<String> = Signal.trigger();
private static final onHttpCheckTrigger:SignalTrigger<{url:String, success:Bool, failReason:Any}> = Signal.trigger();
private static final onHttpFailureTrigger:SignalTrigger<{url:String, failReason:String, handle:HTTPResponse}> = Signal.trigger();
private static final onHttpSuccessTrigger:SignalTrigger<{url:String, handle:HTTPResponse}> = Signal.trigger();
private static final onKeyTrigger:SignalTrigger<{keyCode:Int, isHeld:Bool}> = Signal.trigger();
private static final onKeyUpTrigger:SignalTrigger<Int> = Signal.trigger();
private static final onModemMessageTrigger:SignalTrigger<{
addr:String,
channel:Int,
replyChannel:Int,
message:Dynamic,
distance:Null<Float>
}> = Signal.trigger();
private static final onMonitorResizeTrigger:SignalTrigger<String> = Signal.trigger();
private static final onMonitorTouchTrigger:SignalTrigger<{addr:String, pos:Pos}> = Signal.trigger();
private static final onMouseClickTrigger:SignalTrigger<{button:ButtonType, pos:Pos}> = Signal.trigger();
private static final onMouseDragTrigger:SignalTrigger<{button:ButtonType, pos:Pos}> = Signal.trigger();
private static final onMouseScrollTrigger:SignalTrigger<{dir:Int, pos:Pos}> = Signal.trigger();
private static final onMouseUpTrigger:SignalTrigger<{button:ButtonType, pos:Pos}> = Signal.trigger();
private static final onPasteTrigger:SignalTrigger<String> = Signal.trigger();
private static final onPeripheralTrigger:SignalTrigger<String> = Signal.trigger();
private static final onPeripheralDetachTrigger:SignalTrigger<String> = Signal.trigger();
private static final onRednetMessageTrigger:SignalTrigger<{sender:Int, message:Any, protocol:Any}> = Signal.trigger();
private static final onRedstoneTrigger:SignalTrigger<Noise> = Signal.trigger();
private static final onSpeakerAudioEmptyTrigger:SignalTrigger<String> = Signal.trigger();
private static final onTaskCompleteTrigger:SignalTrigger<{id:Int, success:Bool, failedReason:String}> = Signal.trigger();
private static final onTermResizeTrigger:SignalTrigger<Noise> = Signal.trigger();
private static final onTerminateTrigger:SignalTrigger<Noise> = Signal.trigger();
private static final onTimerTrigger:SignalTrigger<Int> = Signal.trigger();
private static final onTurtleInventoryTrigger:SignalTrigger<Noise> = Signal.trigger();
private static final onWebsocketCloseTrigger:SignalTrigger<String> = Signal.trigger();
private static final onWebsocketFailureTrigger:SignalTrigger<{url:String, failReason:String}> = Signal.trigger();
private static final onWebsocketMessageTrigger:SignalTrigger<{url:String, message:String, isBinary:Bool}> = Signal.trigger();
private static final onWebsocketSuccessTrigger:SignalTrigger<{url:String, handle:Any}> = Signal.trigger();
private static var stopLoop:Bool = false;
@:allow(kernel.Init)
private static function init() {
onAlarm = onAlarmTrigger.asSignal();
onChar = onCharTrigger.asSignal();
onDisk = onDiskTrigger.asSignal();
onDiskEject = onDiskEjectTrigger.asSignal();
onHttpCheck = onHttpCheckTrigger.asSignal();
onHttpFailure = onHttpFailureTrigger.asSignal();
onHttpSuccess = onHttpSuccessTrigger.asSignal();
onKey = onKeyTrigger.asSignal();
onKeyUp = onKeyUpTrigger.asSignal();
onModemMessage = onModemMessageTrigger.asSignal();
onMonitorResize = onMonitorResizeTrigger.asSignal();
onMonitorTouch = onMonitorTouchTrigger.asSignal();
onMouseClick = onMouseClickTrigger.asSignal();
onMouseDrag = onMouseDragTrigger.asSignal();
onMouseScroll = onMouseScrollTrigger.asSignal();
onMouseUp = onMouseUpTrigger.asSignal();
onPaste = onPasteTrigger.asSignal();
onPeripheral = onPeripheralTrigger.asSignal();
onPeripheralDetach = onPeripheralDetachTrigger.asSignal();
onRedstone = onRedstoneTrigger.asSignal();
onSpeakerAudioEmpty = onSpeakerAudioEmptyTrigger.asSignal();
onTaskComplete = onTaskCompleteTrigger.asSignal();
onTermResize = onTermResizeTrigger.asSignal();
onTerminate = onTerminateTrigger.asSignal();
onTimer = onTimerTrigger.asSignal();
onTurtleInventory = onTurtleInventoryTrigger.asSignal();
onWebsocketClose = onWebsocketCloseTrigger.asSignal();
onWebsocketFailure = onWebsocketFailureTrigger.asSignal();
onWebsocketMessage = onWebsocketMessageTrigger.asSignal();
onWebsocketSuccess = onWebsocketSuccessTrigger.asSignal();
}
/**
Start pulling events. Blocking.
**/
@:allow(kernel.Entrypoint)
private static function startEventLoop() {
if (Turtle.isTurtle()) {
turtleLoop();
} else {
runMainLoop();
}
}
private static function turtleLoop() {
var turtleCoroutine = Coroutine.create(runTurtleLoop);
Coroutine.resume(turtleCoroutine);
while (true) {
var eventData = pullEvents();
if (eventData[1] == "turtle_response" || eventData[1] == "tthread") {
Log.debug('Resuming turtle thread');
var result = Coroutine.resume(turtleCoroutine, TableTools.unpack(eventData));
if (!result.success) {
Log.error('Error while running turtle thread: ${result.result}');
}
if (Coroutine.status(turtleCoroutine) == Dead) {
Log.error('Turtle thread died');
}
} else {
fireSignal(eventData[1], eventData);
}
}
}
private static function runTurtleLoop() {
while (!stopLoop) {
Coroutine.yield();
if (stopLoop)
continue;
TurtleMutex.runThreadFunc();
}
}
private static function runMainLoop() {
while (!stopLoop) {
var event:Table<Int, Dynamic> = pullEvents();
var eventName:String = event[1];
try {
fireSignal(eventName, event);
} catch (e:Dynamic) {
Log.error('Error while handling event: $eventName: ${e}');
}
}
}
public static function shutdown() {
// clearing screens
for (screen in Peripheral.getAllScreens()) {
screen.reset();
}
Log.info('Shutting down event loop');
stopLoop = true;
MainTerm.instance.reset();
}
private static function pullEvents():Table<Int, Dynamic> {
return cast TableTools.pack(Coroutine.yield(null));
}
private static function fireSignal(eventName:String, event:Table<Int, Dynamic>) {
switch eventName {
case "alarm":
onAlarmTrigger.trigger(event[2]);
case "char":
onCharTrigger.trigger(event[2]);
case "disk":
onDiskTrigger.trigger(event[2]);
case "disk_eject":
onDiskEjectTrigger.trigger(event[2]);
case "http_check":
onHttpCheckTrigger.trigger({url: event[2], success: event[3], failReason: event[4]});
case "http_failure":
onHttpFailureTrigger.trigger({url: event[2], failReason: event[3], handle: event[4]});
case "http_success":
onHttpSuccessTrigger.trigger({url: event[2], handle: event[3]});
case "key":
onKeyTrigger.trigger({keyCode: event[2], isHeld: event[3]});
case "key_up":
onKeyUpTrigger.trigger(event[2]);
case "modem_message":
onModemMessageTrigger.trigger({
addr: event[2],
channel: event[3],
replyChannel: event[4],
message: event[5],
distance: event[6]
});
case "monitor_resize":
onMonitorResizeTrigger.trigger(event[2]);
case "monitor_touch":
onMonitorTouchTrigger.trigger({addr: event[2], pos: {x: (event[3] : Int) - 1, y: (event[4] : Int) - 1}});
case "mouse_click":
onMouseClickTrigger.trigger({button: ccButtonToEnum(event[2]), pos: {x: (event[3] : Int) - 1, y: (event[4] : Int) - 1}});
case "mouse_drag":
onMouseDragTrigger.trigger({button: ccButtonToEnum(event[2]), pos: {x: (event[3] : Int) - 1, y: (event[4] : Int) - 1}});
case "mouse_scroll":
onMouseScrollTrigger.trigger({dir: event[2], pos: {x: (event[3] : Int) - 1, y: (event[4] : Int) - 1}});
case "mouse_up":
onMouseUpTrigger.trigger({button: ccButtonToEnum(event[2]), pos: {x: (event[3] : Int) - 1, y: (event[4] : Int) - 1}});
case "paste":
onPasteTrigger.trigger(event[2]);
case "peripheral":
onPeripheralTrigger.trigger(event[2]);
case "peripheral_detach":
onPeripheralDetachTrigger.trigger(event[2]);
case "redstone":
onRedstoneTrigger.trigger(null);
case "speaker_audio_empty":
onSpeakerAudioEmptyTrigger.trigger(event[2]);
case "task_complete":
onTaskCompleteTrigger.trigger({id: event[2], success: event[3], failedReason: event[4]});
case "term_resize":
onTermResizeTrigger.trigger(null);
case "terminate":
onTerminateTrigger.trigger(null);
case "timer":
onTimerTrigger.trigger(event[2]);
case "turtle_inventory":
onTurtleInventoryTrigger.trigger(null);
case "websocket_closed":
onWebsocketCloseTrigger.trigger(event[2]);
case "websocket_failure":
onWebsocketFailureTrigger.trigger({url: event[2], failReason: event[3]});
case "websocket_message":
onWebsocketMessageTrigger.trigger({url: event[2], message: event[3], isBinary: event[4]});
case "websocket_success":
onWebsocketSuccessTrigger.trigger({url: event[2], handle: event[3]});
case "endofloop":
EndOfLoop.run();
default:
Log.error('Unknown event: $eventName');
}
}
private static function ccButtonToEnum(button:Dynamic):ButtonType {
switch button {
case 1:
return Left;
case 2:
return Middle;
case 3:
return Right;
default:
throw new Exception("Invalid input");
}
}
@:allow(lib.Debug)
private static function printListenerCount() {
if (onAlarmTrigger.getLength() > 0)
Log.debug("onAlarm: " + onAlarmTrigger.getLength());
if (onCharTrigger.getLength() > 0)
Log.debug("onChar: " + onCharTrigger.getLength());
if (onDiskTrigger.getLength() > 0)
Log.debug("onDisk: " + onDiskTrigger.getLength());
if (onDiskEjectTrigger.getLength() > 0)
Log.debug("onDiskEject: " + onDiskEjectTrigger.getLength());
if (onHttpCheckTrigger.getLength() > 0)
Log.debug("onHttpCheck: " + onHttpCheckTrigger.getLength());
if (onHttpFailureTrigger.getLength() > 0)
Log.debug("onHttpFailure: " + onHttpFailureTrigger.getLength());
if (onHttpSuccessTrigger.getLength() > 0)
Log.debug("onHttpSuccess: " + onHttpSuccessTrigger.getLength());
if (onKeyTrigger.getLength() > 0)
Log.debug("onKey: " + onKeyTrigger.getLength());
if (onKeyUpTrigger.getLength() > 0)
Log.debug("onKeyUp: " + onKeyUpTrigger.getLength());
if (onModemMessageTrigger.getLength() > 0)
Log.debug("onModemMessage: " + onModemMessageTrigger.getLength());
if (onMonitorResizeTrigger.getLength() > 0)
Log.debug("onMonitorResize: " + onMonitorResizeTrigger.getLength());
if (onMonitorTouchTrigger.getLength() > 0)
Log.debug("onMonitorTouch: " + onMonitorTouchTrigger.getLength());
if (onMouseClickTrigger.getLength() > 0)
Log.debug("onMouseClick: " + onMouseClickTrigger.getLength());
if (onMouseDragTrigger.getLength() > 0)
Log.debug("onMouseDrag: " + onMouseDragTrigger.getLength());
if (onMouseScrollTrigger.getLength() > 0)
Log.debug("onMouseScroll: " + onMouseScrollTrigger.getLength());
if (onMouseUpTrigger.getLength() > 0)
Log.debug("onMouseUp: " + onMouseUpTrigger.getLength());
if (onPasteTrigger.getLength() > 0)
Log.debug("onPaste: " + onPasteTrigger.getLength());
if (onPeripheralTrigger.getLength() > 0)
Log.debug("onPeripheral: " + onPeripheralTrigger.getLength());
if (onPeripheralDetachTrigger.getLength() > 0)
Log.debug("onPeripheralDetach: " + onPeripheralDetachTrigger.getLength());
if (onRedstoneTrigger.getLength() > 0)
Log.debug("onRedstone: " + onRedstoneTrigger.getLength());
if (onSpeakerAudioEmptyTrigger.getLength() > 0)
Log.debug("onSpeakerAudioEmpty: " + onSpeakerAudioEmptyTrigger.getLength());
if (onTaskCompleteTrigger.getLength() > 0)
Log.debug("onTaskComplete: " + onTaskCompleteTrigger.getLength());
if (onTermResizeTrigger.getLength() > 0)
Log.debug("onTermResize: " + onTermResizeTrigger.getLength());
if (onTerminateTrigger.getLength() > 0)
Log.debug("onTerminate: " + onTerminateTrigger.getLength());
if (onTimerTrigger.getLength() > 0)
Log.debug("onTimer: " + onTimerTrigger.getLength());
if (onTurtleInventoryTrigger.getLength() > 0)
Log.debug("onTurtleInventory: " + onTurtleInventoryTrigger.getLength());
if (onWebsocketCloseTrigger.getLength() > 0)
Log.debug("onWebsocketClose: " + onWebsocketCloseTrigger.getLength());
if (onWebsocketFailureTrigger.getLength() > 0)
Log.debug("onWebsocketFailure: " + onWebsocketFailureTrigger.getLength());
if (onWebsocketMessageTrigger.getLength() > 0)
Log.debug("onWebsocketMessage: " + onWebsocketMessageTrigger.getLength());
if (onWebsocketSuccessTrigger.getLength() > 0)
Log.debug("onWebsocketSuccess: " + onWebsocketSuccessTrigger.getLength());
}
}