edusperoni / nativescript-mqtt

MQTT 3.1.1 for Nativescript
Apache License 2.0
12 stars 3 forks source link

compatibility with emitter #11

Closed amlibtest closed 5 years ago

amlibtest commented 5 years ago

is it possible to use this library to connect with emitter? Emitter does not use user or password and they suggest to just pass null values. However, I'm getting this error while trying that: Invalid type object for userName..

If I use the channel and key emitter provides, I get this error: java.net.URISyntaxException: Illegal character in path at index 24: ws://[http://172.23.0.72]:9034. So they don't replace those values

edusperoni commented 5 years ago

Just pass empty strings as username and password instead of null. Also, your URL is wrong. You have to pass the host, not the URL:

mqtt_clientOptions: ClientOptions = {
    host: "172.23.0.72",
    port: 9034,
    useSSL: false
};

Also, please provide code examples and use the GitHub issue template to report bugs instead of deleting it all and writing the problem itself.

amlibtest commented 5 years ago

Sorry to bother you again @edusperoni , what you said did work to connect, but now I'm getting an error while trying to subscribe.

I'm testing on an Android 7.0 device using NativeScript with Angular. I'm providing the requested information:

  "dependencies": {
    "@angular/animations": "~8.0.0",
    "@angular/common": "~8.0.0",
    "@angular/compiler": "~8.0.0",
    "@angular/core": "~8.0.0",
    "@angular/forms": "~8.0.0",
    "@angular/http": "~8.0.0-beta.10",
    "@angular/platform-browser": "~8.0.0",
    "@angular/platform-browser-dynamic": "~8.0.0",
    "@angular/router": "~8.0.0",
    "@nstudio/nativescript-cardview": "^1.0.0",
    "@nstudio/nativescript-floatingactionbutton": "^1.0.1",
    "@types/crypto-js": "^3.1.43",
    "@types/d3-ease": "^1.0.8",
    "@types/node": "^12.7.3",
    "buffer": "^5.4.2",
    "crypto-js": "^3.1.9-1",
    "d3-ease": "^1.0.5",
    "md5": "^2.2.1",
    "moment": "^2.24.0",
    "nativescript-angular": "~8.0.0",
    "nativescript-appversion": "^1.4.2",
    "nativescript-background-http": "^3.4.1",
    "nativescript-camera": "^4.5.0",
    "nativescript-geolocation": "^5.1.0",
    "nativescript-imagepicker": "^7.0.0",
    "nativescript-loading-indicator": "^2.5.2",
    "nativescript-mapbox": "^4.3.1",
    "nativescript-mqtt": "^1.2.0",
    "nativescript-oauth2": "^2.1.0",
    "nativescript-permissions": "^1.3.6",
    "nativescript-plugin-firebase": "^9.0.0",
    "nativescript-social-share": "^1.5.2",
    "nativescript-sqlite": "^2.3.3",
    "nativescript-theme-core": "~1.0.4",
    "nativescript-toast": "^2.0.0",
    "nativescript-ui-chart": "^4.0.2",
    "nativescript-ui-dataform": "^3.6.0",
    "nativescript-ui-listview": "^6.4.2",
    "nativescript-ui-sidedrawer": "~6.0.0",
    "nativescript-unit-test-runner": "^0.6.4",
    "ng2-translate": "^5.0.0",
    "reflect-metadata": "~0.1.12",
    "rxjs": "^6.5.2",
    "rxjs-compat": "^6.5.2",
    "tns-core-modules": "~5.4.0",
    "zone.js": "~0.9.1"
  },
  "devDependencies": {
    "@angular/compiler-cli": "~8.0.0",
    "@ngtools/webpack": "~8.0.0",
    "@types/karma-chai": "0.1.1",
    "@types/mocha": "5.2.7",
    "chai": "4.2.0",
    "codelyzer": "~4.5.0",
    "karma": "4.2.0",
    "karma-chai": "0.1.0",
    "karma-mocha": "1.3.0",
    "karma-nativescript-launcher": "0.4.0",
    "karma-webpack": "4.0.2",
    "mocha": "6.1.4",
    "nativescript-dev-sass": "^1.7.0",
    "nativescript-dev-typescript": "~0.10.0",
    "nativescript-dev-webpack": "~0.24.0",
    "tslint": "~5.11.0"
  }

When I try to subscribe, I'm getting this error from message that was received (even without sending any): Message received: {"req":1,"status":400,"message":"the request was invalid or cannot be otherwise served"}

This is my service so far:

import { Injectable } from "@angular/core";
import {MQTTClient, ClientOptions, SubscribeOptions} from "nativescript-mqtt";
import {Message} from "nativescript-mqtt/common";
import * as moment from 'moment';

@Injectable()
export class EmitterService {
    emitterStarted: boolean = false;
    emitterKey: string;
    emitterChannel: string;
    emitterTTL: number;
    emitterInstance: any;
    callback: any;
    retry: number = 0;
    turnOff: boolean = false;

    constructor(){};

    public startEmitter(channel, key, ttl, cb){
        this.callback = cb;
        this.emitterChannel = channel;
        this.emitterKey = key;
        let date = ttl;
        this.emitterTTL = moment(new Date(date)).valueOf();
        let test = (this.emitterChannel.replace(/\//g, '%2F'))
        let path = "/"+this.emitterKey+"/"+this.emitterChannel;
        let mqtt_clientOptions: ClientOptions = {
            host: "172.23.0.72",
            port: 9034,
            path: path,
            useSSL: false,
            cleanSession: true
        };
        this.emitterInstance = new MQTTClient(mqtt_clientOptions);
        this.emitterInstance.onConnectionFailure.on((err) => {
            console.log("Connection failed: " + err);
        });
        this.emitterInstance.onConnectionSuccess.on(() => {
            console.log("Connected successfully!");
            this.retry = 0;
            this.turnOff = false;
            try {
                const opts: SubscribeOptions = {
                    qos: 0
                };
                this.emitterInstance.subscribe("message", opts); // The error comes after calling this line
            }
            catch (e) {
                console.log("Caught error: " + e);
            }
        });
        this.emitterInstance.onConnectionLost.on((err) => {
            console.log("Connection lost: " + err);
            if(this.retry < 3 && !this.turnOff){
                this.startEmitter(channel, key, ttl, cb);
                this.retry++;
            }else{
                console.log("Max number of consecutive retries for emitter reached, or manually turned off");
            }
        });
        this.emitterInstance.onMessageArrived.on((message: Message) => {
            console.log("Message received: " + message.payload); // this is the message printed
            cb(message.payload)
        });
        this.emitterInstance.onMessageDelivered.on((message: Message) => {
            console.log("Message delivered: " + message.payload);
        });
        try{
            console.log("previous to connect");
            this.emitterInstance.connect("", "");
        }
        catch (e) {
            console.log("Caught error: " + e);
        }                
        this.emitterStarted = true;
    }

    public stopEmitter(){
        console.log("stopping emitter");
        //sólo se aplica si en verdad fue activado el emitter. sólo puede haber uno a la vez
        if(this.emitterStarted && this.emitterKey && this.emitterChannel){
            this.turnOff = true;
            this.emitterInstance.unsubscribe("message");
            this.emitterInstance.disconnect();
            this.emitterStarted = false;
            this.emitterKey = null;
            this.emitterChannel = null;
            this.emitterTTL = null;
            this.callback = null;
        }
    }
}

To call my service from my components, I'm just doing this:

import { EmitterService } from "../../services/emitter.service";
export class MyComponent {

    private emitterService: EmitterService;

    public constructor(){
        this.emitterService = new EmitterService();
    }

    public startEmitter(cb){
        // getting values of key, channel and ttl, cb is a callback function
        this.emitterService.startEmitter(channel, key, ttl, cb);
    }
}

As far as I have read, I need to pass my key and channel in mqtt_clientOptions.path. Maybe there is something else I'm missing? My path has this form : /haUMO_GM63frMddobV0LhTV1hoMTgcs7/57/13438/65881/

amlibtest commented 5 years ago

I found the answer: path has nothing to do with this, so it can be ignored. When calling subscribe, instead of the topic I should pass my channel