Using WebSocket.js as a JS module in place of React component - javascript

I have a Websocket.JS that is defined as the following :
class Websocket extends Component {
constructor(props) {
super(props);
const url = Config.ws + Config.baseEndPoint + Config.pen;
const protocol = this.props.protocol;
const doesLogging = (this.props.doesLogging === "true");
this.state = {"url": url,
"protocol": protocol,
"socket": new WebSocket(url, protocol),
"doesLogging": doesLogging};
};
onOpen() {
}
onMessage(msg) {
}
onClose() {
}
render() {
return (
<div id="websocket"></div>
);
}
}
export default Websocket;
And use it in the app.js like this:
import Websocket from './services/websocket';
<Websocket handleMessage={(msg) => this.messageReceived(msg.data)} />
However, I want to use it just as a module without it being represented like an HTML element. Is there any possible I can do that ?

I do not think that interaction via websockets must be presented in your code by using any kind of the UI library. Therefore:
class YourWebsocket{
constructor(protocol, url, enableLogging) {
this.url = url;
this.protocol = protocol;
this.loggingEnabled = enableLogging;
this.socket = new WebSocket(url, protocol);
this.socket.onopen = (ev) => this.onOpen();
// Assign more handlers here
}
onOpen() {
}
onMessage(msg) {
}
onClose() {
}
send(data, callback)
{
var listener = (e) =>
{
var reply = e.data;
if(replyIsForOurRequest) //Here you should come up with the logic to decide if this is reply for your request
{
this.socket.removeEventListener("message", listener);
callback(reply);
}
};
this.socket.addEventListener("message", listener);
this.socket.send(data);
}
}
export default YourWebsocket;
And in your app.js somewhere in componentDidMount method:
import YourWebsocket from './services/YourWebsocket';
class App extends React.Component
{
componentDidMount()
{
this.webSocket = new YourWebsocket();
//...
}
}

Related

Add Service name in the Opentelemetry for a JavaScript application

I am trying to integrate Opentelemetry (Otl) in my Angular application to trace the frontend calls. Everything works fine and I am able to see the calls in the Zipkin.
But the only problem is that it is showing it as "unknown_service" in the Zipkin interface.
Below is my entire Angular code and Zipkin screenshot as well. This is just a sample application. But my requirement is that I am going to integrate the Opentelemetry code in the http interceptor so that it will be easy to maintain at one place instead of every service call. Also service.name should be passed dynamically so that it will be traced in Zipkin.
How can I add a service name before it gets called?
import { Component, OnInit } from '#angular/core';
import {ZipkinServicesService} from './zipkin-services.service';
// Opentelemetry components
import { context, trace } from '#opentelemetry/api';
import { ConsoleSpanExporter, SimpleSpanProcessor } from '#opentelemetry/tracing';
import { WebTracerProvider } from '#opentelemetry/web';
import { XMLHttpRequestInstrumentation } from '#opentelemetry/instrumentation-xml-http-request';
import { ZoneContextManager } from '#opentelemetry/context-zone';
import { CollectorTraceExporter } from '#opentelemetry/exporter-collector';
import { B3Propagator } from '#opentelemetry/propagator-b3';
import { registerInstrumentations } from '#opentelemetry/instrumentation';
import { ZipkinExporter } from '#opentelemetry/exporter-zipkin';
#Component({
selector: 'app-zipkin-integration',
templateUrl: './zipkin-integration.component.html',
styleUrls: ['./zipkin-integration.component.scss']
})
export class ZipkinIntegrationComponent implements OnInit {
respData: string;
webTracerWithZone;
constructor(
public zipkinService: ZipkinServicesService,
) {
const providerWithZone = new WebTracerProvider();
const options = {
url: 'http://localhost:9411/api/v2/spans',
serviceName: 'interceptor-example',// This is NOT working.
}
const exporter = new ZipkinExporter(options);
const zipKinProcessor = new SimpleSpanProcessor(exporter);
providerWithZone.addSpanProcessor(zipKinProcessor);
providerWithZone.addSpanProcessor(new SimpleSpanProcessor(new ConsoleSpanExporter()));
providerWithZone.addSpanProcessor(new SimpleSpanProcessor(new CollectorTraceExporter()));
providerWithZone.register({
contextManager: new ZoneContextManager(),
propagator: new B3Propagator(),
});
registerInstrumentations({
instrumentations: [
new XMLHttpRequestInstrumentation({
ignoreUrls: [/localhost:8090\/sockjs-node/],
propagateTraceHeaderCorsUrls: [
'https://httpbin.org/post',
],
}),
],
});
this.webTracerWithZone = providerWithZone.getTracer('example-tracer-web');
}
ngOnInit(): void {
}
zipGet (){
let i = 10;
const span1 = this.webTracerWithZone.startSpan(`files-series-info-${i}`);
let postData = [{
no : 2,
emp : 3
}];
context.with(trace.setSpan(context.active(), span1), () => {
this.zipkinService.httpGet(postData).subscribe( (data: any) => {
this.respData = data;
// Opentelemetry after response.
trace.getSpan(context.active()).addEvent('fetching-span1-completed');
span1.end();
});
});
}
zipPost (){
let postData = [{
no : 1,
emp : 2
}];
let i = 10;
const span1 = this.webTracerWithZone.startSpan(`files-series-info-${i}`);
context.with(trace.setSpan(context.active(), span1), () => {
this.zipkinService.httpPost(postData).subscribe( (data: any) => {
this.respData = data;
// Opentelemetry after response.
trace.getSpan(context.active()).addEvent('fetching-span1-completed');
span1.end();
});
});
}
}
Service name must be set via resource as per the specification. I am not sure which version of js libs you are using. This should get you the service name.
import { Resource } from '#opentelemetry/resources';
import { ResourceAttributes } from '#opentelemetry/semantic-conventions'
...
...
const provider = new WebTracerProvider({
resource: new Resource({
[ResourceAttributes.SERVICE_NAME]: "interceptor-example"
}),
});
use providerConfig to set service name. follow code set service name to "SPA Test".
import { Resource } from '#opentelemetry/resources';
import { SemanticResourceAttributes } from '#opentelemetry/semantic-conventions'
import { BatchSpanProcessor } from '#opentelemetry/sdk-trace-base';
import { WebTracerProvider } from '#opentelemetry/sdk-trace-web';
import { ZipkinExporter, ExporterConfig } from '#opentelemetry/exporter-zipkin';
const providerConfig = {
resource: new Resource({
[SemanticResourceAttributes.SERVICE_NAME]: "SPA Test"
}),
};
const provider = new WebTracerProvider(providerConfig);
const zipkinOptions: ExporterConfig = {
url: "http://localhost:9411/api/v2/spans"
};
const exporter = new ZipkinExporter(zipkinOptions);
const zipkinProcessor = new BatchSpanProcessor(exporter);
provider.addSpanProcessor(zipkinProcessor);
provider.register();
var tracer = provider.getTracer(CustomersComponent.name, "0.1.0");
var span = tracer.startSpan(CustomersComponent.name);
console.info(span);
span.end();

Executing class instance method that is in an array (javascript)

EDIT: Solved by renaming the this.powerOn declaration in all of the class constructors.
I have a function that pulls data from a database and stores it in the appropriate array(s). I have another function that iterates through said array(s) and instantiates a new instance of a class based on a targeted property & these instances are stored in a separate array. I am having trouble triggering methods of said instances that, as far as I can tell, should be apart of them.
Currently this is how I am attempting to handle this:
const SourceModel = require('../models/Source');
const DisplayModel = require('../models/Display');
const Roku = require('../_data/sdk/Roku');
const Sony = require('../_data/sdk/Sony');
const driversArray = [];
const liveDriverInstances = [];
// Returns new class instance based on DriverModel
class instantiatedDriverClass {
constructor(DriverModel, DriverIPAddress, DriverPort) {
let driverClasses = {
Roku,
Sony
};
return new driverClasses[DriverModel](DriverIPAddress, DriverPort)
}
}
// Pull sources, displays, ..., from DB
const getDevicesFromDB = async () => {
sourcesArray = await SourceModel.find();
displaysArray = await DisplayModel.find();
};
// Create new array from sources, displays, ..., arrays & iterate to instantiate matching driver class
const loadDeviceDriversToRuntime = async () => {
await getDevicesFromDB();
sourcesArray.forEach((source) => driversArray.push(source));
displaysArray.forEach((display) => driversArray.push(display));
driversArray.forEach((driver) => {
liveDriverInstances.push(new instantiatedDriverClass(driver.driver.driverModel, driver.ipaddress, driver.port));
});
};
// Executed by server after connection to DB is established
const importDrivers = () => {
loadDeviceDriversToRuntime();
}
module.exports = importDrivers, driversArray;
The two classes (so far) that I am trying to execute methods on are Roku and Sony. Roku extends MediaPlayer and Sony extends Display. MediaPlayer and Display extends Commands. Code for Roku class:
const MediaPlayer = require('./MediaPlayer');
class Roku extends MediaPlayer {
constructor(ipaddress, port, powerOnDelay, powerOffDelay) {
super();
let url = `https://${ipaddress}:${port}`
this.powerOn = `${url}/powerOn`;
this.powerOff = `${url}/powerOff`;
this.up = `${url}/up;`
this.down = `${url}/down`;
this.left = `${url}/left`;
this.right = `${url}/right`;
this.enter = `${url}/enter`;
this.select = `${url}/select`;
this.back = `${url}/back`;
this.backspace = `${url}/backspace`;
this.exit = `${url}/exit`;
this.guide = `${url}/guide`;
this.menu = `${url}/menu`;
}
powerOn() {
super.powerOn(this.powerOn);
}
powerOff() {
super.powerOff(this.powerOff);
}
}
module.exports = Roku;
Code for MediaPlayer class:
const Commands = require('./Commands');
class MediaPlayer extends Commands {
constructor(powerOn, powerOff, up, down, left, right, enter, select, back, backspace, exit, guide, menu) {
super();
this.powerOn = powerOn;
this.powerOff = powerOff;
this.up = up;
this.down = down;
this.left = left;
this.right = right;
this.enter = enter;
this.select = select;
this.back = back;
this.backspace = backspace;
this.exit = exit;
this.guide = guide;
this.menu = menu;
}
powerOn() {
super.powerOn(this.powerOn);
}
powerOff() {
super.powerOff(this.powerOff);
}
}
module.exports = MediaPlayer;
Code for Commands class:
class Commands {
constructor(command) {
this.command = command;
}
powerOn(command) {
console.log("Something")
}
powerOff(command) {
console.log("Something")
}
up(command) {
console.log("Something")
}
down(command) {
console.log("Something")
}
left(command) {
console.log("Something")
}
right(command) {
console.log("Something")
}
enter(command) {
console.log("Something")
}
play(command) {
console.log("Something")
}
pause(command) {
console.log("Something")
}
select(command) {
console.log("Something")
}
guide(command) {
console.log("Something")
}
menu(command) {
console.log("Something")
}
back(command) {
console.log("Something")
}
delete(command) {
console.log("Something")
}
speed1(command) {
console.log("Something")
}
speed2(command) {
console.log("Something")
}
speed3(command) {
console.log("Something")
}
HDMI1(command) {
console.log("Something")
}
HDMI2(command) {
console.log("Something")
}
HDMI3(command) {
console.log("Something")
}
}
module.exports = Commands;
As far as I understand, the methods powerOn() and powerOff() should be accessible when an instance of Roku or Sony is created. If, however, I try to do something like liveDriverInstances[0].powerOn() I get an error liveDriverInstances[0].powerOn is not a function. When I run console.log(liveDriverInstances[0]) I get this response:
Roku {
command: undefined,
powerOn: 'https://192.168.1.205:8060/powerOn',
powerOff: 'https://192.168.1.205:8060/powerOff',
up: 'https://192.168.1.205:8060/up;',
down: 'https://192.168.1.205:8060/down',
left: 'https://192.168.1.205:8060/left',
right: 'https://192.168.1.205:8060/right',
enter: 'https://192.168.1.205:8060/enter',
select: 'https://192.168.1.205:8060/select',
back: 'https://192.168.1.205:8060/back',
backspace: 'https://192.168.1.205:8060/backspace',
exit: 'https://192.168.1.205:8060/exit',
guide: 'https://192.168.1.205:8060/guide',
menu: 'https://192.168.1.205:8060/menu'
}
So the data is being passed down from the Roku instance inheriting from MediaPlayer inheriting from Commands, but I don't have the methods. Looks like it is just getting the constructor method, but nothing more. Have I defined something incorrectly here?
On the constructor of Roku class. you are initializing the powerOn as a String . This will replace the function powerOn() declared.
constructor(ipaddress, port, powerOnDelay, powerOffDelay) {
...
this.powerOn = `${url}/powerOn`;
...
}
You can make this work by renaming the url fields
constructor(ipaddress, port, powerOnDelay, powerOffDelay) {
...
this.powerOnUrl = `${url}/powerOn`;
...
}
powerOn() {
super.powerOn(this.powerOnUrl);
}

Is it possible to call a react-360 method from a native Module?

I am working on a VR project which is has 2 user roles, a leader (who sets up and configures a VR session) and clients (who connect to this session).
I am using a Native module to perform a DOM overlay in which several buttons related to session configuration are displayed for the leader. I was wondering if it is possible to call a function within the React360 code directly from a Native Module (i.e. not as a callback as the event would originate from the Native Module)?
This could be a complete anti-pattern, I can't seem to see a way of doing it...
I actually got this working with the following:
In client.js I passed the context to the DOM overlay native module:
const r360 = new ReactInstance(bundle, parent, {
// Add custom options here
fullScreen: true,
cursorVisibility: "visible",
nativeModules: [
// Create an instance of the DOM overlay module and pass the context
ctx => new DashboardModule(ctx, domDashboardContainer)
],
...options,
});
In the dashboard native module :
const eventToOb = (event) => {
const eventOb = {};
for (let key in event) {
const val = event[key];
if (!(lodash.isFunction(val) || lodash.isObject(val))) {
eventOb[key] = val;
}
}
return eventOb;
};
....
constructor(ctx, overlayContainer) {
super('DashboardModule');
...
this._rnctx = ctx;
this._bridgeName = 'BrowserBridge';
}
onButtonClick() {
....
this._emit('nativeButtonClicked', event);
}
_emit(name, event) {
if (!this._rnctx) {
return;
}
const eventOb = eventToOb(event);
this._rnctx.callFunction(this._bridgeName, 'notifyEvent', [name, eventOb]);
}
...
and in my index.js
...
import BatchedBridge from 'react-native/Libraries/BatchedBridge/BatchedBridge';
import lodash from 'lodash';
class BrowserBridge {
constructor() {
this._subscribers = {};
}
subscribe(handler) {
const key = String(Math.random());
this._subscribers[key] = handler;
return () => {
delete this._subscribers[key];
};
}
notifyEvent(name, event) {
lodash.forEach(this._subscribers, handler => {
handler(name, event);
});
}
}
const browserBridge = new BrowserBridge();
BatchedBridge.registerCallableModule(BrowserBridge.name, browserBridge);
....
constructor(props) {
super(props);
this.onBrowserEvent = this.onBrowserEvent.bind(this);
...
}
componentWillMount() {
this.unsubscribe = browserBridge.subscribe(this.onBrowserEvent);
}
onBrowserEvent(name, event) {
// Do action on event here
}
componentWillUnmount() {
if (this.unsubscribe) {
this.unsubscribe();
delete this.unsubscribe;
}
}
If there is a better way of doing this please let me know.

infinite loop with angularjs httpInterceptor injecting service using toastr

I'm getting and issue with my httpInterceptor and my toastr Service. It always make infinite loop
AlertService (using toastr)
class AlertService {
constructor(toastr) {
this.toastr = toastr;
this.toastrCommonOpts = {
positionClass: "toast-bottom-center",
allowHtml: true,
closeButton: true,
}
}
notificationError (msg, title) {
let errorMsg = msg || 'error';
this.toastr.error(errorMsg, title || '', this.toastrCommonOpts);
};
notificationWarning(msg, title) {
let warningMsg = msg || 'warning';
this.toastr.warning(warningMsg, title || '', this.toastrCommonOpts);
}
notificationSuccess(msg, title, duration) {
let successMsg = msg || 'Success';
this.toastr.success(successMsg, title || '', this.toastrCommonOpts);
}
}
AlertService.$inject = ['toastr'];
export default AlertService ;
myHttpInterceptor
class HttpInterceptor {
constructor() {
['request', 'response']
.forEach((method) => {
if(this[method]) {
this[method] = this[method].bind(this);
}
});
}
}
class MyHttpInterceptor extends HttpInterceptor{
constructor(AlertService) {
super();
this.AlertService = AlertService;
}
request(config) {
this.AlertService.notificationSuccess();
return config;
};
response(response){
this.AlertService.notificationSuccess();
return response;
}
}
MyHttpInterceptor.$inject = ['AlertService'];
export default MyHttpInterceptor;
myModule
import MyHttpInterceptor from './myHttpInterceptor';
import AlertService from "./alert.service";
export default angular.module('app.core', [toastr])
.service('AlertService', AlertService)
.factory('MyHttpInterceptor', MyHttpInterceptor)
.config(($httpProvider) => {
$httpProvider.defaults.withCredentials = true;
$httpProvider.interceptors.push('MyHttpInterceptor');
});
I extends myHttpInterceptor and bind my methods to prevent loosing context 'this' (cf : angularjs http interceptor class (ES6) loses binding to 'this' ). I did not succeed to use arrowFunctions as class methods.
I also tried to do it following this issue
Would any of you have already encountered this problem?
Thanks :)

Perform certain base class method calls only once instead of every instance of the class?

I have a class that performs a login request on instantiation, I only want this login request to be
performed by the base class and for all other instances to acknowledge that the login
has been performed. Can anyone recommend how this can be achieved, would this be a use-case for making
the login function static?
// Example
class Content {
constructor() {
this.performLogin()
}
performLogin() { // will making this static achieve my request?
// go fetch if 1st time
// else bypass this step
}
performLogout() {
// perform log out once only
}
}
class ContentOne extends Content {
constructor() {
super()
}
doSomethingElse() {
//...
}
}
class ContentTwo extends Content {
constructor() {
super()
}
alertUser() {
//...
}
}
const contentOne = new ContentOne()
const contentTwo = new ContentTwo()
A better design would be to have a LoginService that would manage that. If already logged in, it would just ignore the request. For example,
class LoginService {
constructor() {
this.isLoggedIn = false;
}
login() {
if (this.isLoggedIn) { return; }
// do work
this.isLoggedIn = true;
}
}
class Content {
constructor(loginService) {
this.loginService = loginService;
this.performLogin()
}
performLogin() {
this.loginService.login();
}
performLogout() {
// perform log out once only
}
}
const loginService = new LoginService();
const contentOne = new ContentOne(loginService);
const contentTwo = new ContentTwo(loginService);
Making a function static won't prevent something being called more than once.

Categories

Resources