Vertx Java deploy a JavaScript verticle with Future Callback - vertx3

i would like deploy inside my Java VertX a javascript Verticle. Of course, this is not a problem. The question is, how can i give them a callback ?
My Java Code:
Vertx.clusteredVertx(vertxOptions, res ->
{
if (res.succeeded()) {
logger.info("Cluster ready, starting verticle deploy");
/*
* React JS Server Deploy
*/
Future< String > reactVerticleFuture = Future.future();
vertx.executeBlocking(future ->
{
vertx.deployVerticle("dist/server.js", options, deployResult ->
{
if (deployResult.succeeded()) {
future.complete();
} else {
future.fail(deployResult.cause());
}
});
} , reactVerticleFuture.completer());
CompositeFuture.all(..., reactVerticleFuture).setHandler(ar ->
{
/*
* deploy http listener and health endpoint
*/
});
} else {
logger.error(res.cause().getMessage(), res.cause());
}
});
My server.js:
exports.vertxStartAsync = function(startFuture) {
console.log('vertxStartAsync')
var eb = vertx.eventBus()
var consumer = eb.consumer('httpGetWebChannel', function (message) {
})
consumer.completionHandler(function (res, res_err) {
if (res_err == null) {
console.log("The handler registration has reached all nodes");
startFuture.complete()
} else {
console.log("Registration failed!");
startFuture.fail()
}
});
}
Of course, my server.js is bigger and this need's some time for starting. In my clustered Vertx i get during the start some messages that something blocks my bus.
How can i fix this ?
Thanks
Marcel

Ok, we found a solution ( alexvetter - thanks for your patience).
The problem is that i build my server.js file with webpack and after building, the exports block is inside a function.
This is the working solution:
webpack.config.js
var WrapperPlugin = require('wrapper-webpack-plugin');
...
plugins: [
new WrapperPlugin({
header: 'exports.vertxStartAsync = function(startFuture) {\n',
footer: '}\n'
}),
...
]
...
server.js
var eb = vertx.eventBus()
var consumer = eb.consumer('httpGetWebChannel', function (message) {
...
})
consumer.completionHandler(function (res, res_err) {
if (res_err == null) {
console.log("The handler registration has reached all nodes");
startFuture.complete()
} else {
console.log("Registration failed!");
startFuture.fail()
}
});
Thanks

Related

Service Worker registers but doesn't cache

I'm new to service workers and I'm running into an issue with my implementation. My goal is to create a runtime cache for images and videos. I've looked at the workbox implementation but it hasn't worked for me. I see that my service worker successfully registers at the top-level scope of my app but for some reason, it seems like some of the code in my service worker file doesn't get executed. The main issue is that the event listeners from my service worker don't seem to get called (including registerRoute), and therefore, the Cache doesn't ever get created.
I'm not sure if this is related to the issue I'm having but when I look at the console messages, it seems like the code from sw.js may be run prior to the service worker registration:
console messages
I've been stuck on this problem for a while so I would appreciate some help if anyone has run into this issue, thanks!
// main.js (in a Vue 2 app)
if (process.env.NODE_ENV === "production") {
window.addEventListener("load", () => {
if ("serviceWorker" in navigator) {
navigator.serviceWorker
.register(`/sw.js`)
.then(() => {
console.log("Service worker registered!");
navigator.serviceWorker.ready.then((registration) => {
registration.update();
console.log('Service Worker: ready');
});
})
.catch((error) => {
console.warn("Error registering service worker:");
console.warn(error);
});
}
});
}
// sw.js
import { registerRoute } from "workbox-routing";
import { CacheFirst } from "workbox-strategies";
import { CacheableResponsePlugin } from "workbox-cacheable-response";
import { RangeRequestsPlugin } from "workbox-range-requests";
import { clientsClaim } from "workbox-core";
const CACHE_PREFIX = "background-slideshow-cache";
const CACHE_VERSION = "v1";
const CACHE_RUNTIME = "runtime";
const BACKGROUND_SLIDESHOW_CACHE = `${CACHE_PREFIX}-${CACHE_RUNTIME}-${CACHE_VERSION}`;
clientsClaim();
const addToCache = async (url) => {
const cache = await caches.open(BACKGROUND_SLIDESHOW_CACHE);
if (!(await cache.match(url))) {
await cache.add(url);
}
};
const cacheFirstStrategy = new CacheFirst({
cacheName: BACKGROUND_SLIDESHOW_CACHE,
plugins: [
new CacheableResponsePlugin({
statuses: [200],
}),
new RangeRequestsPlugin(),
],
});
self.addEventListener("message", (event) => {
if (event.data && event.data.message) {
if (event.data.message === "SKIP_WAITING") {
self.skipWaiting();
}
}
});
self.addEventListener("install", (event) => {
console.log('Service worker: fetch event', event);
})
console.log("Service Worker: in file");
registerRoute(
({ request }) => {
const { destination } = request;
console.log("Service Worker:", "request", request);
return destination === "video" || destination === "image";
},
({ event, request }) => {
// console.log("Service Worker: in the 2nd param", event, request);
event.respondWith(async () => {
await addToCache(request.url);
return cacheFirstStrategy.handle({ request });
});
}
);
After many hours of debugging, I realized that the minification of sw.js at build time was the reason this code wasn't able to execute. I decided to use uglifyjs-webpack-plugin in my webpack config and this solved the issue!

Providing two combined Reducers for my redux saga store prevents my websocket channel message from triggering, but only one does not?

Configured my store this way with redux toolkit for sure
const rootReducer = combineReducers({
someReducer,
systemsConfigs
});
const store = return configureStore({
devTools: true,
reducer: rootReducer ,
// middleware: [middleware, logger],
middleware: (getDefaultMiddleware) => getDefaultMiddleware({ thunk: false }).concat(middleware),
});
middleware.run(sagaRoot)
And thats my channel i am connecting to it
export function createSocketChannel(
productId: ProductId,
pair: string,
createSocket = () => new WebSocket('wss://somewebsocket')
) {
return eventChannel<SocketEvent>((emitter) => {
const socket_OrderBook = createSocket();
socket_OrderBook.addEventListener('open', () => {
emitter({
type: 'connection-established',
payload: true,
});
socket_OrderBook.send(
`subscribe-asdqwe`
);
});
socket_OrderBook.addEventListener('message', (event) => {
if (event.data?.includes('bids')) {
emitter({
type: 'message',
payload: JSON.parse(event.data),
});
//
}
});
socket_OrderBook.addEventListener('close', (event: any) => {
emitter(new SocketClosedByServer());
});
return () => {
if (socket_OrderBook.readyState === WebSocket.OPEN) {
socket_OrderBook.send(
`unsubscribe-order-book-${pair}`
);
}
if (socket_OrderBook.readyState === WebSocket.OPEN || socket_OrderBook.readyState === WebSocket.CONNECTING) {
socket_OrderBook.close();
}
};
}, buffers.expanding<SocketEvent>());
}
And here's how my saga connecting handlers looks like
export function* handleConnectingSocket(ctx: SagaContext) {
try {
const productId = yield select((state: State) => state.productId);
const requested_pair = yield select((state: State) => state.requested_pair);
if (ctx.socketChannel === null) {
ctx.socketChannel = yield call(createSocketChannel, productId, requested_pair);
}
//
const message: SocketEvent = yield take(ctx.socketChannel!);
if (message.type !== 'connection-established') {
throw new SocketUnexpectedResponseError();
}
yield put(connectedSocket());
} catch (error: any) {
reportError(error);
yield put(
disconnectedSocket({
reason: SocketStateReasons.BAD_CONNECTION,
})
);
}
}
export function* handleConnectedSocket(ctx: SagaContext) {
try {
while (true) {
if (ctx.socketChannel === null) {
break;
}
const events = yield flush(ctx.socketChannel);
const startedExecutingAt = performance.now();
if (Array.isArray(events)) {
const deltas = events.reduce(
(patch, event) => {
if (event.type === 'message') {
patch.bids.push(...event.payload.data?.bids);
patch.asks.push(...event.payload.data?.asks);
//
}
//
return patch;
},
{ bids: [], asks: [] } as SocketMessage
);
if (deltas.bids.length || deltas.asks.length) {
yield putResolve(receivedDeltas(deltas));
}
}
yield call(delayNextDispatch, startedExecutingAt);
}
} catch (error: any) {
reportError(error);
yield put(
disconnectedSocket({
reason: SocketStateReasons.UNKNOWN,
})
);
}
}
After Debugging I got the following:
The Thing is that when I Provide one Reducer to my store the channel works well and data is fetched where as when providing combinedReducers I am getting
an established connection from my handleConnectingSocket generator function
and an empty event array [] from
const events = yield flush(ctx.socketChannel) written in handleConnectedSocket
Tried to clarify as much as possible
ok so I start refactoring my typescript by changing the types, then saw all the places that break, there was a problem in my sagas.tsx.
Ping me if someone faced such an issue in the future

Reconnect WebSocket in Angular 5 with Rxjs observable and observer

In any case, if my application got disconnected from WebSocket I am not able to reconnect it. I am attaching the sample code please suggest me the idea to how I can reconnect WebSocket and initialize my identity on web socket server again.
I have made my application with the help of this tutorial.
https://tutorialedge.net/typescript/angular/angular-websockets-tutorial/
I have written the same code in my application except for my application requirement.
The tutorial that I have been followed does not have the feature to reconnect the WebSocket in any case like internet break or by some reason our WebSocket server got restart because I am running my WebSocket server with SupervisorD and it will automatically restart if WebSocket server get to stop in any case
My application is in production and many customers are using now so I can not change all flow and recreate the code for WebSocket in this application.
I am adding all code that I am using
websocket.service.ts
import { Injectable } from '#angular/core';
import * as Rx from 'rxjs/Rx';
#Injectable()
export class WebsocketService {
connected: boolean = false;
initialized: boolean= false;
constructor() { }
private subject: Rx.Subject<MessageEvent>;
public connect(url): Rx.Subject<MessageEvent> {
if (!this.subject) {
this.subject = this.create(url);
// console.log("Successfully connected: " + url);
}
return this.subject;
}
private create(url): Rx.Subject<MessageEvent> {
let ws = new WebSocket(url);
// here i am trying to reconnect my websocket
// setInterval (function () {
// if (ws.readyState !== 1) {
// ws = new WebSocket(url);
// this.initialized = false;
// }
// console.log(this.initialized);
// if (ws.readyState == 1 && this.initialized == false) {
// ws.send('{"type":"add",
"t":"14bfa6xxx", "from_numbers":
["xxxx","xxxxx"], "platform":"xxxx"}');
// this.initialized = true;
// }
// console.log(this.initialized);
// }, 4000);
let observable = Rx.Observable.create(
(obs: Rx.Observer<MessageEvent>) => {
ws.onmessage = obs.next.bind(obs);
ws.onerror = obs.error.bind(obs);
ws.onclose = obs.complete.bind(obs);
return ws.close.bind(ws);
})
let observer = {
next: (data: Object) => {
if (ws.readyState === WebSocket.OPEN) {
if (data['type'] == 'add') {
console.log("Connection Initialized");
}
ws.send(JSON.stringify(data));
}
}
}
return Rx.Subject.create(observer, observable);
}
}
Chat.service.ts
import { Injectable } from '#angular/core';
import { Observable, Subject } from 'rxjs/Rx';
import { WebsocketService } from './websocket.service';
#Injectable()
export class ChatService {
public messages: Subject<Message>;
constructor(wsService: WebsocketService, private authService: AuthService) {
this.messages = <Subject<Message>>wsService
.connect(socket_url)
.map((response: MessageEvent): Message => {
const data = JSON.parse(response.data);
console.log(data);
return data;
});
}
}
and finality I have used this in our component to subscribe message.
constructor(private chatService: ChatService,) {
this.socketMessages();
}
socketMessages() {
this.chatService.messages.subscribe(msg => {
console.log(msg)
});
}

How can I override jasmine's buildExpectationResult in order to modify message() function?

I am using protractor for my e2e tests and jasmine2 as framework. I am using a plugin for html reporter with screenshots ( html-report for protractor ).
In these reports there will be shown a list of all failed/passed expects. When the expect fails I get a descriptive message of the expectation. However when the expect passes I only see the word: Passed. The reason behind that is that jasmine overrides the message when the expect passes.
That is done in the following file:
node_modules/protractor/node_modules/jasmine/node_modules/jasmine-core/lib/jasmine-core/jasmine.js
getJasmineRequireObj().buildExpectationResult = function () {
function buildExpectationResult(options) {
var messageFormatter = options.messageFormatter || function () {
},
stackFormatter = options.stackFormatter || function () {
};
var result = {
matcherName: options.matcherName,
message: message(),
stack: stack(),
passed: options.passed
};
if (!result.passed) {
result.expected = options.expected;
result.actual = options.actual;
}
return result;
function message() {
if (options.passed) {
// Here is the message overriden
return 'Passed.';
} else if (options.message) {
return options.message;
} else if (options.error) {
return messageFormatter(options.error);
}
return '';
}
function stack() {
if (options.passed) {
return '';
}
var error = options.error;
if (!error) {
try {
throw new Error(message());
} catch (e) {
error = e;
}
}
return stackFormatter(error);
}
}
return buildExpectationResult;
};
What I wanted is to override this function in my protractor protractor.conf.js file. And replace it with one with the desired behaviour.
I've tried to do so unsuccessfully doing the following:
onPrepare: function () {
jasmine.buildExpectationResult = function () {
function buildExpectationResult(options) {
var messageFormatter = options.messageFormatter || function () {
},
stackFormatter = options.stackFormatter || function () {
};
return {
matcherName: options.matcherName,
expected: options.expected,
actual: options.actual,
message: message(),
stack: stack(),
passed: options.passed
};
function message() {
if (options.message) {
return options.message;
} else if (options.error) {
return messageFormatter(options.error);
}
return "";
}
function stack() {
if (options.passed) {
return "";
}
var error = options.error;
if (!error) {
try {
throw new Error(message());
} catch (e) {
error = e;
}
}
return stackFormatter(error);
}
}
return buildExpectationResult;
};
}
Then my questions is: What is the right way to override a jasmine method?
Since we use gulp task to run protractor tests, we override the lib (like jasmine lib) as one of the gulp task with custom copy. We do that as part of installation or every test execution.
I didn't find any good way to override it unless we create another npm module.
I had the same issue, I'm not sure if my solution
onPrepare: function () {
// ...
jasmine.Spec.prototype.addExpectationResult = function(passed, data, isError) {
var buildExpectationResult = function(options) {
var messageFormatter = options.messageFormatter || function() {},
stackFormatter = options.stackFormatter || function() {};
var result = {
matcherName: options.matcherName,
message: message(),
stack: stack(),
passed: options.passed
};
if(!result.passed) {
result.expected = options.expected;
result.actual = options.actual;
}
return result;
function message() {
if (options.passed) {
return options.message ? options.message : 'Passed';
} else if (options.message) {
return options.message;
} else if (options.error) {
return messageFormatter(options.error);
}
return '';
}
function stack() {
if (options.passed) {
return '';
}
var error = options.error;
if (!error) {
try {
throw new Error(message());
} catch (e) {
error = e;
}
}
return stackFormatter(error);
}
}
var exceptionFormatter = jasmine.ExceptionFormatter;
var expectationResultFactory = function(attrs) {
attrs.messageFormatter = exceptionFormatter.message;
attrs.stackFormatter = exceptionFormatter.stack;
return buildExpectationResult(attrs);
}
var expectationResult = expectationResultFactory(data);
if (passed) {
this.result.passedExpectations.push(expectationResult);
} else {
this.result.failedExpectations.push(expectationResult);
if (this.throwOnExpectationFailure && !isError) {
throw new j$.errors.ExpectationFailed();
}
}
};
// ...
}

Future functions in DART working with ORACLE DART pub

I'm using oracledart pub, and need to get the results returned as Map to the main function, I know it is a FUTURE function, and read about FUTURE, but looks still not clear for me, or I'm doing something wrong in my code, my function is as below:
void main() {
var ORAresults = <Map>[];
ORA()
.then((results) => ORAresults = results)
.catchError((e) => 'Sorry, something wrong!');
}
ORA() {
var results = <Map>[];
connect(
"SYSTEM","pswd",
"(DESCRIPTION="
"(ADDRESS=(PROTOCOL=TCP)(HOST=localhost)(PORT=1521))"
"(CONNECT_DATA=(SERVICE_NAME=XE)(SERVER=DEDICATED)))")
.then(
(oracleConnection) {
var resultset = oracleConnection.select("select * from vendors");
while(resultset.next()) {
results.add({"code":"vCode 1","name": "${resultset.getStringByName('NAME')}"});
}
print('the results inside $results'); // this works very well
return results;
},
onError: (error) {
print("Failed to connect: $error");
});
}
When I run the above, I get this error:
Breaking on exception: object of type NoSuchMethodError
the file dart:core-patch_object_patch.dart is opening, and pointing to:
noSuchMethod(Invocation invocation) {
=> return _noSuchMethod(invocation.isMethod, // this line is being highlighted!
internal.Symbol.getName(invocation.memberName),
invocation._type,
invocation.positionalArguments,
_symbolMapToStringMap(invocation.namedArguments));
}
I thing the error is due to something wrong here, because if I removed these lines, the error disappear.:
ORA()
.then((results) => ORAresults = results)
.catchError((e) => 'Sorry, something wrong!');
any help pls.
Your ORA() function does not return the Future it uses. Change the connect( line to return connect(, and it should work.
When you do ORA().then(...), you're using ORA()'s return value as a Future, but your ORA() function returns null (it has no return statement, so it returns null by default). What you really want to do is return the Future you're building on with the connect().
Thanks #Tonio and #Robert, I think now I understood the meaning of the FUTURE better :)
I was able to solve the issue, based on your hints and explanations, as below:
in the server.dart
void handlePost(HttpRequest req) {
HttpResponse res = req.response;
switch (req.uri.path) {
...
case '/getVendors':
getVendors(req);
break;
default:
break;
}
}
void getVendors(HttpRequest req) {
HttpResponse res = req.response;
addCorsHeaders(res);
print('${req.method}: ${req.uri.path}');
var vendors = <Map>[];
connect(
"SYSTEM",
"pswrd",
"(DESCRIPTION="
"(ADDRESS=(PROTOCOL=TCP)(HOST=localhost)(PORT=1521))"
"(CONNECT_DATA=(SERVICE_NAME=XE)(SERVER=DEDICATED)))")
.then(
(oracleConnection) {
var resultset = oracleConnection.select("select * from vendors");
while(resultset.next()) {
vendors.add({"code":"${resultset.getStringByName('CODE')}","name": "${resultset.getStringByName('NAME')}"});
}
res.write(JSON.encode(vendors));
res.close();
},
onError: (error) {
print("Failed to connect: $error");
});
}
and in the client.dart
main(){
HttpRequest request;
String serverResponse = '';
...
}
void submit(){
request = new HttpRequest();
request.onReadyStateChange.listen(onData_getvendors);
var url = 'http://127.0.0.1:8004/getVendors';
request.open('POST', url);
request.send('');
}
onData_getvendors(_){
if (request.readyState == HttpRequest.DONE && request.status == 200) { // Data saved OK.
for(Map vendor in JSON.decode(request.responseText)){
vendor..children.add(new OptionElement(value: vendor['code'], data: vendor['name']));
}
else if (request.readyState == HttpRequest.DONE &&
request.status == 0) { // Status is 0...most likely the server isn't running.
serverResponse=request.responseText;
}
}

Resources