How to initialize code modules in workers - factory

I'm a big step further in my attempt to make an image decoder from nodes usable in the browser. the code already works in the program just like its node version. but if that were my goal to only use it in the program, I wouldn't have needed to bring it locally into my program from nodes. I just tested it to see if it works and it does and that was a huge step.
my goal is to be able to use the decoder in workers. I have seen in another decoder that works with workers that the decoder is integrated via a factory function. maybe you are now wondering why i don't use the decoder that works with workers???
the reason is that said decoder can only read 8-bit images. fast-png can read 16 bit images and that's exactly what i need.
but I'm not very familiar with embedding code in factory functions. I have never tried this in connection with imports and therefore my first question:
can factory functions be used at all in connection with import?
if so, I'm obviously doing something wrong, because it doesn't work.
can anyone show me an example of how to do it correctly?
If it is helpful I can also create a repository on github.
(function(global, factory){
typeof exports === 'object' && typeof module !== 'undefined' ? factory(exports) :
typeof define === 'function' && define.amd ? define(['exports'], factory) :
(global = typeof globalThis !== 'undefined' ? globalThis : global || self, factory(global.png = {}));
})(function (exports) {
import {IOBuffer} from '../resources/libs/fast-png/IOBuffer.js';
import { inflate, Inflate as Inflator } from '../resources/libs/fast-png/pako.js';
import {pngSignature, crc} from '../resources/libs/fast-png/common.js';
import {ColorType, CompressionMethod, FilterMethod, InterlaceMethod} from '../resources/libs/fast-png/internalTypes.js';
class PngDecoder extends IOBuffer {
constructor(data, options = {}) {
super(data);
//many parameters, I have deleted them here so that
//there are not hundreds of lines of code here and the essentials are not lost
}//end constructor
//... many methods, i deleted them to keep track
}//end class
//...
//... many functions, i deleted them to keep track
//...
function decodePng(data, options) {
const decoder = new PngDecoder(data, options);
return decoder.decode();
}
exports.decodePng = decodePng;
}));//end of factory function
async function imageLoader() {
const arrayBuffer = await(await fetch('./resources/textures/depth1.png')).arrayBuffer();
const imageData = await png.decodePng(arrayBuffer);
const data = imageData.data;
postMessage(data);
}
//will call when the worker is called
imageLoader();

Related

How to serve multiple interfaces in Capnproto

In the calculator example, I have added a new interface in the capnp file like below:
interface Main {
getCalculator #0 () -> (calculator :Calculator);
}
My objective is to make use of multiple interfaces through one implementation Main. How can I achieve this? The extra client code is below (when I try to use calculator it throws a null capability exception):
capnp::EzRpcClient client1(argv[1]);
Main::Client main = client1.getMain<Main>();
auto& waitScope1 = client1.getWaitScope();
auto request1 = main.getCalculatorRequest();
auto evalPromise1 = request1.send();
auto response1 = evalPromise1.wait(waitScope1);
auto calculator = response1.getCalculator();
auto request = calculator.evaluateRequest();
request.getExpression().setLiteral(123);
// Send it, which returns a promise for the result (without blocking).
auto evalPromise = request.send();
// Using the promise, create a pipelined request to call read() on the
// returned object, and then send that.
auto readPromise = evalPromise.getValue().readRequest().send();
// Now that we've sent all the requests, wait for the response. Until this
// point, we haven't waited at all!
auto response = readPromise.wait(waitScope1);
KJ_ASSERT(response.getValue() == 123);
Changes to the server's main implementation file are given below:
class MainImpl : public Main::Server {
public:
kj::Promise<void> getCalculator(GetCalculatorContext context) override {
context.getResults();
return kj::READY_NOW;
}
};
The main function in server serves MainImpl. I do get the calculator object but how can I further invoke methods on that object?
Your getCalculator() function on the server side does not do anything right now. You need to actually set the result if you want the Calculator to get back to the client. That's why you get your "null capability exception".
Something like this:
class MainImpl : public Main::Server {
public:
kj::Promise<void> getCalculator(GetCalculatorContext context) override {
context.getResults().setCalculator(<the calculator capability>);
return kj::READY_NOW;
}
};
That will require you to create the Calculator client on the server side (i.e. you won't do Calculator::Client calculator = client.getMain<Calculator>(); on the client side anymore, since calculator will come from getCalculator()).

Is CoroutineScope(SupervisorJob()) runs in Main scope?

I was doing this code lab
https://developer.android.com/codelabs/android-room-with-a-view-kotlin#13
and having a question
class WordsApplication : Application() {
// No need to cancel this scope as it'll be torn down with the process
val applicationScope = CoroutineScope(SupervisorJob())
// Using by lazy so the database and the repository are only created when they're needed
// rather than when the application starts
val database by lazy { WordRoomDatabase.getDatabase(this, applicationScope) }
val repository by lazy { WordRepository(database.wordDao()) }
}
private class WordDatabaseCallback(
private val scope: CoroutineScope
) : RoomDatabase.Callback() {
override fun onCreate(db: SupportSQLiteDatabase) {
super.onCreate(db)
INSTANCE?.let { database ->
scope.launch {
var wordDao = database.wordDao()
// Delete all content here.
wordDao.deleteAll()
// Add sample words.
var word = Word("Hello")
wordDao.insert(word)
word = Word("World!")
wordDao.insert(word)
// TODO: Add your own words!
word = Word("TODO!")
wordDao.insert(word)
}
}
}
}
this is the code I found, as you can see, it is directly calling scope.launch(...)
my question is that:
isn't all the Room operations supposed to run in non-UI scope? Could someone help me to understand this? thanks so much!
Is CoroutineScope(SupervisorJob()) runs in Main scope?
No. By default CoroutineScope() uses Dispatchers.Default, as can be found in the documentation:
CoroutineScope() uses Dispatchers.Default for its coroutines.
isn't all the Room operations supposed to run in non-UI scope?
I'm not very familiar specifically with Room, but generally speaking it depends if the operation is suspending or blocking. You can run suspend functions from any dispatcher/thread. deleteAll() and insert() functions in the example are marked as suspend, therefore you can run them from both UI and non-UI threads.

How can I ensure the writable flag is true before send()?

I am creating an abstraction layer for Dart WebSocket who is also protocol compatible with Socket.IO, but it has a problem I can not solve.
The follow code convert the HttpRequest into a WebSocket and save the socket instance on the Transport... Here you can see I change the value of the writable flag to true in order to inform the socket is open.
WebSocketTransformer.upgrade(req).then((socket) {
this._socket = socket;
this.writable = true;
this._socket.handleError(() {
this.onClose();
});
// start listen the socket;
socket.listen((packet) {
this.onData(packet);
});
}).catchError((Exception e) {
this.onError('Can\'t conenct with the socket.', e.toString());
});
(The full code can be founded here.)
When I debug the code first the debugger stops inside that closure and only then stops here, where the check is make but writable still false :/
void flush([_]) {
if (this._readyState != SocketStates.closed && this.transport.writable &&
!this._writeBuffer.isEmpty) {
(The full code can be founded here)
I really need help...
Your constructor makes an async call but doesn't return a future (not possible in a constructor)
WebSocketTransformer.upgrade(req).then
Use a static method instead which returns Future<WebSocketTransformer> or use an init method where you initiaize your class after creation.
There might be other problems but yor code does not show how you use your class therefore its hard to tell.

Haxe application exits when deployed to windows

I am making a game engine in haxe/openfl. so far it's just supposed to display the image that belongs to the thing object. what I have built so far runs perfectly on when deployed as a flash application, but closes instantly when I deploy it as a windows application. It just creates a blank screen in html5. I have not tested other targets. I am using HIDE, and every time it crashes, HIDE brings up the message: "File c:\Users\Adu\Documents\HaxeProjects\Downloaded\Export\windows\cpp\bin\Downloaded.exe was changed. Reload?" and gives me the options yes or no. My answer doesn't seem to change the situation. when I manually go into the export directory and run the application, it gives the error: "Error Custom([file_write,stderr]). Here is my code:
Main:
package;
import openfl.display.Graphics;
import openfl.Assets;
import openfl.display.Bitmap;
import openfl.display.Sprite;
import openfl.events.Event;
import openfl.Lib;
import openfl.text.TextField;
import openfl.text.TextFormat;
import openfl.ui.Keyboard;
import openfl.events.*;
class Main
{
static var obj(default,default):ObjectManager; //contains the list that all gameobjects add themselves to
static var stage = Lib.current.stage;
public static function main() // this is the gameloop
{
// static entry point
startUp();
var running = true; // gives me a way to exit the gameloop
while (running)
{
logic();
render();
Lib.current.stage.addEventListener(KeyboardEvent.KEY_DOWN, function(event)
{
if (event.keyCode == Keyboard.ESCAPE)
{
running=false;
}
});
}
}
static function startUp() // runs once, when the game is started
{
obj= new ObjectManager();
stage.align = openfl.display.StageAlign.TOP_LEFT;
stage.scaleMode = openfl.display.StageScaleMode.NO_SCALE;
}
static function logic() // loops, this handles the logic
{
var thing = new GameObject("assets/pixel_thing.png", 1, obj);
var mech = new GameObject("assets/mechwarrior.png", 0, obj);
}
static function render() // runs right after logic and draws everything to the screen
{
for (i in obj.objects) //iterates through a list of gabeobjects and draws them, it is 2 dimensional so that I can draw objects in blocks
{
for (j in i)
{
Lib.current.addChild(j);
}
}
}
}
GameObject:
package ;
import openfl.display.BitmapData;
import openfl.Assets;
import openfl.display.Bitmap;
import openfl.display.Sprite;
import openfl.events.Event;
import openfl.Lib;
import openfl.text.TextField;
import openfl.text.TextFormat;
class GameObject extends Sprite
{
public function new(?image:String, zOrder:Int, objectManager:ObjectManager) // image is the image, zorder is which layer it's drawn on, lower layers are drawn on top objectmanager is just there to help me pass the list to the object
{
super();
var data = Assets.getBitmapData(image);//this is the image data
var bitmap:Bitmap = new Bitmap(data);//this is the actual image
Lib.current.stage.addChild(bitmap);//this sraws the image when the object is instantiated
objectManager.objects[zOrder].push(this);// this adds it to the list of objects
}
}
ObjectManager:
package ;
class ObjectManager
{
public var objects = new Array<Array<GameObject>>();
}
why is it that it works on flash but not windows? How do I fix this?
First off - this doesn't work fine on flash either. Are you running this in the flash debug player? If you don't, which I assume is the case, you won't see any exceptions.
There's a null reference error at this line:
objectManager.objects[zOrder].push(this);// this adds it to the list of objects
You are accessing the array at index zOrder, which doesn't exist. objects is being initialized to [], which does not include the "inner arrays" (it can't, really, how would it know how many of them there should be?).
Now, Windows builds don't give you very helpful debug information by default. A simple way around is to use neko (which mostly behaves the same as hxcpp builds, except it compiles faster and performs worse) for debugging, where you get a stacktrace by default on crashes.
Sure enough, it's the same issue as in flash, the only difference is that native builds crash while flash just "ignores it" and tries to carry on.
Invalid field access : objects
Called from GameObject::new line 92
Called from GameObject::$init line 83
Called from Main::logic line 61
Called from Main::main line 38
Called from Reflect::callMethod line 58
Called from ApplicationMain::main line 91
Called from openfl.Lib::create line 113
For better hxcpp build debug info, you might want to have a look at the crashdumper lib.

Recreate a Google Swiffy animation once destroy() is called

I'm trying to remove a Google swiffy (v 5.2.0) animation and then readd it at a later date.
In terms of the running animation there doesn't seem to be any problem, but the code triggers an error: TypeError: Cannot redefine property: Animation_fla.MainTimeline at which point all AS3 in the movie stops working. This seems to be because the destroy method is not removing references to the AS3 code within the swiffy runtime. I've spent some time trying to step through the code but it's pretty incomprehensible.
Below is a stripped out version of all I'm doing with swiffy - calling init again after calling destroy will trigger this TypeError. I've tried to reinitialise the swiffy runtime itself but this causes a similar error.
var stage;
function init() {
stage = new swiffy.Stage(domElement, swiffyJson);
stage.start();
}
function destroy() {
stage.destroy();
stage = null;
}
The only solution I've come up with is a pretty horrible hack. It seem Swiffy really doesn't like to recreate animations after they've been destroyed. I've had some success with detaching the Swiffy from the DOM but retaining it's reference in memory. I then had to hack the runtime to enable pause and restart. I could then reattach the original Swiffy without having to destroy it. This is in v5.2.0 downloaded from https://www.gstatic.com/swiffy/v5.2/runtime.js, after putting the runtime through jsbeautifier.org
Around line 5640 after the M.releaseCapture function I added the following function:
M.hackPause = function (bool) {
if(this.hackPaused === bool) return;
if(this.hackPaused) {
bi(ef(this.qh.yl, this.qh));
}
this.hackPaused = bool;
};
The around line 7137, replace the AK[I].yl function with the following:
Ak[I].yl = function () {
if (this.bh) {
var a = Date.now();
a >= this.Mf && (this.tl.ei(), this.Mf += (s[Xb]((a - this.Mf) / this.sl) + 1) * this.sl);
this.tl.lc();
if(!this.tl.hackPaused) {
bi(ef(this.yl, this))
}
}
};
What this is doing is preventing the requestAnimationFrame or setTimeout from firing and therefore effectively pausing the animation.
I've tried to expose a gotoAndStop function within the runtime also, but I couldn't manage to find the scope amongst the code. In the meantime, using a hack from this post - Is it possible to pause/resume/manipulate a swiffyobject from JS? we can do this with a brute force approach by adding an enter frame event to the flash movie and testing for a change in Flashvars. Below is the Document Class we've been using for our animations. It's worth noting that Swiffy doesn't seem to like AS3 Classes that extend from the same base class, it throws the same cannot redefine property error, so we've duplicated the code from here in the Document class of each of our Flash animations. I've also got a method in there that allows dispatching events from the AS3 to a javascript function called onSwiffyEvent:
package {
import flash.display.MovieClip;
import flash.net.URLRequest;
import flash.net.navigateToURL;
import flash.events.Event;
import flash.utils.setTimeout;
public class BaseAnimation extends MovieClip {
private var _request:URLRequest;
private var _pageName:String;
private var _movieName:String;
public function BaseAnimation() {
_request = new URLRequest();
_pageName = getFlashVar('pageName');
_movieName = getFlashVar('movieName');
addEventListener(Event.ENTER_FRAME, jsListen);
}
private function getFlashVar(name:String):String {
var flashVar:String = stage.loaderInfo.parameters[name] || '';
stage.loaderInfo.parameters[name] = '';
return flashVar;
}
public function dispatchJSEvent(eventName:String, param:String = ''):void {
_request.url = "javascript:onSwiffyEvent('" + eventName + "', '" + param + "', '" + _movieName + "', '" + _pageName + "');";
navigateToURL(_request, "_self");
}
private function jsListen(e:Event):void {
var mode:String = getFlashVar('mode');
if(mode.length) {
switch(mode) {
case 'stop':
stop();
break;
case 'play':
play();
break;
case 'gotoStart':
gotoAndStop('start');
break;
}
}
}
}
}
Swiffy also doesn't seem to like gotoAndStop(0) so I've had to set a frame label of 'start' on the first frame of the animation.
With all this horrible hackery in place, we're able to remove and restart Swiffy animations. The only issue we've found is that detaching and reattaching has caused issues with embedded SVG fonts and we've ended up converting all text to outlines. The above is used like so:
You can call it on the swiffy stage like so:
var stage = new swiffy.Stage(domObject, swiffyObj);
stage.start();
// when reading to remove this element from the DOM do the following:
stage.setFlashVars('mode=gotoStart');
setTimeout(function () {
// timeout is required to ensure that the enterframe listener has time to run
stage.hackPause(true); // paused animation
}, 100);
// you can then remove the containing div from the DOM, but retain it in memory
// after you reattach the div to the DOM, ensuring we've kept hold of our stage variable in memory, you can restart it like this:
stage.hackPause(false); // resumes javascript requestAnimationFrame
stage.setFlashVars('mode=play'); // resumes flash animation
Hope this helps someone, but I also really hope Google start to expose some kind of JS API or ExternalInterface to the Swiffy runtime to give us more control over what is really a pretty great tool.
Try creating a copy of the swiffyobject before passing it to swiffy.Stage(). Swiffy is modifying the object upon instantiation, so with a copy you can simply recreate after destroy()

Resources