Category Archives: Javascript

Επικοινωνία με το πρωτόκολλο Xmpp μέσω XMPP.js: Προβλήματα και workaround.

Ο παρακάτω οδηγός είναι υπό συχνή ανανέωση καθώς καταγράφω της εμπειρίες μου όπως αναπτύσσω εφαρμογές με την βιβλιοθήκη xmpp.js

Στο master thesis μου έπρεπε να αναπτύξω μια εφαρμογή σε electron και Node.js που ουσιαστικά ήταν ένας xmpp client. Κατά την ανάπτυξη αυτής συνάντησα τα εξής προβλήματα αξιοποιώντας αυτήν την βιβλιοθήκη, τα οποιά στην συνέχεια σας δείχνω πως τα έχω επιλύσει.

Σύμφωνα με την τεκμηρίωση της βιβλιοθήκης ο συνιστώμενος κώδικας είναι ο εξής:



const xmpp = client({
service: 'xmpp://example.com',
domain: 'example',
username: 'user',
password: 'password',
})

xmpp.on('error', err => {
console.error('❌', err.toString())
})

xmpp.on('offline', () => {
console.log('🛈', 'offline')
})

xmpp.on('online', async address => {
console.log('🗸', 'online as', address.toString())

// Sends a chat message to itself
const message = xml(
'message',
{type: 'chat', to: address},
xml('body', 'hello world')
)
xmpp.send(message)
})

xmpp.on('stanza', stanza => {
console.log('⮈', stanza.toString())
xmpp.stop()
})

xmpp.start()
 Όμως έτσι σκέτος μου παρουσιάζει το εξής πρόβλημα, λόγο ότι  by default ενεργοποιεί SSL/TLS συνδέσεις, δεν μου επιτρέπει να διαχειρηστώ την περίπτωση που η SSL/TLS σύνδεση χρησιμοποιεί Self-signed πιστοποιητικά. Αυτό είναι γενικότερο θέμα της Node.js στον τρόπου που διαχειρίζεται το SSL. Λύνετε απλά θέτοντας την μεταβλητή περιβάλλοντος NODE_TLS_REJECT_UNAUTHORIZED στην τιμή 0. Πέρα από τις εντολές κονσόλας npm κλπ κλπ μπορεί να γίνει και μέσω κώδικα javascript, απλά προσθέστε στην αρχικό script που εκτελεί η εφαρμογή σας την παρακάτω γραμμή κώδικα:
process.env.NODE_TLS_REJECT_UNAUTHORIZED=0

Καλή ιδέα είναι να εκτελείτε η παραπάνω όταν είστε σε περιβάλλον ανάπτυξης και μόνο.

Πέρα από αυτό όταν κάνεις έναν client πρέπει να μπορείς να εμφανίζεις τουλάχιστον τον κατάλληλο μήνυμα είτε στον τελικό χρήστη είτε στον sysadmin έτσι πρέπει να διαχειρίζεσε κατάστάσεις όπως:

  • Ο χρήστης δίνει λάθος server ή o client δεν μπορεί να επικοινωνήσει στον server.
  • Ο χρήστης δίνει λάθος credentials.

Προσωπικά λόγο της φύσης της Node.js ο τρόπος που μπορούσα να το διαχειριστώ είναι ελέγχοντας μέσω regular expression (well μπορεί να μην σου αρέσει αλλά θέλοντας και μη πρέπει να μάθεις να γράφεις PCRE συμβατές regular expressions) το μήνυμα του σφάλματος. Ένα snippet κώδικα από την εφαρμογή μου που χρησιμοποιεί electron (που έχει ενσωματωμένη nodejs) είναι:

const errorRegex = {
DNS_NOT_FOUND: /^getaddrinfo ENOTFOUND/,
AUTH_FAILED: /^not-authorized/,
}; 
xmpp.on('error', (err) => {
  console.error('Error occured', err.message, Object.getPrototypeOf(err));
  if (errorRegex.DNS_NOT_FOUND.test(err.message)) {
      console.error('Connection Error', `The provided server ${connectionInfo.service} does not exist.`);
     // Add handling stuff here
     destructClient(xmpp);
  } else if (errorRegex.AUTH_FAILED.test(err.message)) {
    console.error('Authentication Error', 'The provided username and password are not valid');
    // Add further handling here
    destructClient(xmpp);
  }
});

Ουσιαστικά ανάλογα με το ποιο regular expression ορισμένο στο αντικείμενο errorRegex εφαρμόζω τον κατάλληλο έλεγχο.

Ακόμη εν λόγο βιβλιοθήκη κάνει αυτόματες επανασυνδέσεις, και το κάνει ΕΠ’ ΑΠΕΙΡΟΝ, πράγμα που δίνει άσχημο user experience στον τελικό χρήστη. Γι αυτό το περιορίζω σε 10 προσπάθειες που με το παρακάτω κομμάτι κώδικα:

let connectionCounter = 10;
xmpp.reconnect.on('reconnecting', () => {
  if (connectionCounter===0) {
    destructClient();
  }
  connectionCounter-=1;
})

Ουσιαστικά κάνω abort με xmpp.stop() που καλείτε εντός της destructClient(). Για μήνυμα σφάλματος δοκιμάστε το να το εκτυπώσετε στο event error:

xmpp.on('error', (e)=>{
 if (err.code === 'ECONNREFUSED' && connectionCounter === 0) {
   dialogsHelper.errorDialog('Connection Error', `Failed to connect into ${err.address}.`);
 }
}

Αξιοδημείωτε δε είναι ότι η διεύθυνση σύνδεσης έρχετε μαζί με το error όπως και ο τύπος του error στη μεταβλητή στιγμιότυπου error.

Επιπλέων ένα θέμα είναι ότι θέλω να τρέχω έναν κώδικα μια φορά όταν ο χρήστης κάνει login, για κάποιο λόγο η βιβλιοθήκη καλεί 2 φορές το event login, όμως δεν θέλουμε να τρέχουν κάποια πράγματα 2 φορές έτσι θα πρέπει να ορίζουμε κάποια μορφής flag που να μην επιτρέπει την εκτέλεση κάποιων κομματιών κώδικα 2 φορές (πχ. να εμφανίζει στον τελικό χρήστη δύο φορές ένα μήνυμα σύνδεσης):


let flag=false

//Some code goes here
xmpp.on('offline', () => {
 flag=false;
}

xmpp.on('online',(address) => {
  if(!flag){
   flag=true;
   console.log(`You logged in as ${address}`); 
  }
})

Επιπλέον τα μηνύματα που αποστέλλονται μέσω XMPP ονομάζονται stanzas και υπάρχονυ πάρα πολλά είδη. Για κάθε ένα είδος ορίζω και μια ξεχωριστή function όπως βλέπετε στον παρακάτω κώδικα:

xmpp.on('stanza',(stanza)=> {
  try {
 if(presenceReply(stanza) !== false) return;
 if(handleRoster(stanza) !== false) return;
 // Add your function here
 } catch(e) {
   console.error(e);
 }
});

Αυτή η δομή λόγο όχι χρησιμοποιεί πολλές function για να επεξεργαστεί καταλλήλως το εισερχόμενο μύνημα πρέπει στην αρχή να ελέγχετε ο τύπος με τον εξής τρόπο πχ στην function presenceReply:

const presenceReply = (stanza) => {
  if(!stanza.is('presence')) return false;
  if(loginAddress.bare().equals(from.bare())) return false;
  
  const from = jid(stanza.attrs.from);
  const message = xml('presence', { to: stanza.attrs.from });
  console.log('Sent To', stanza.attrs.from);
  sendMessage(message);
  return true;
};

Όπως βλέπουμε καλύτερα να ελέγχουμε εάν ο τύπος ΔΕΝ είναι αυτός που ζητάμε και να επιστρέφουμε, από προσωπική εμπειρία αυτό είναι ένας bulletrpoof τρόπος να αποτρέπει στο να σπάει το πρόγραμμα σε ΠΟΛΛΕΣ περιπτώσεις. Ακόμη όπως βλέπετε όταν το μύνημα δεν είναι ο κατάλληλος τύπος επιτρέφουμε false και την τιμή αυτή την ελέγχουμε στην callback το event ‘stanza’, εάν ελέγχθηκε τότε προχωράμε στην επόμενη function η ιδέα είναι ότι δεν θέλουμε να εκτελέσουμε κάποια function εάν ήδη έχουμε επεξεργαστεί το μήνυμα.

Τέλος ο έλεγχος γίνετε ελέγχοντας εάν η τιμή ΔΕΝ είναι false με το σύμβολο !== λόγο ότι με αυτόν τον τρόπο σε επιτιχία μπορούμε επιτρέπουμε να ΜΗΝ επιστρέφει τιμή,
εναλλακτική προσέγγιση είναι η χρήση reqular expression που επιστρέφετε με την μέθοδο stanza.toString(). Ακόμη δε, χρήζει σημείωσης, όλη η σειρά των ifs είναι σε ένα try ... catch block επιτρέποντας όποιο σφάλμα συμβαίνει να ΜΗΝ κρασάρει όλη την εφαρμογή αλλά να μένει και να διαχειρίζεται τοπικά. Ενδεικτικά βάζω console.error αλλά μπορεί στην θέση του να οποιοδήποτε κομμάτι κώδικα.

Ακόμη όταν θέλετε να τραβήξετε όλους τους φίλους και τους κάνετε render, καλό είναι να ακολουθήσετε την εξής διαδικασία (δοκιμασμένη σε electron που ουσιαστικά είναι ένας browser και nodejs που σε αυτόν τρέχω και την xmpp.js άρα δεν υπάρχει communication overhead):

  1. Αποστείλετε ένα roster request.
  2. Όταν το λάβετε κάντε το render.
  3. Όταν γίνει render αποστείλετε ότι είστε online με το δικό σας presence

Για ποιο ολοκληρωμένη εικόνα δείτε την παρακάτω εικόνα, σε περίπτωση web client συνηστώ η χρήση websocket λόγο φόρτου επικοινωνίας.
Διαδικασία μεταξύ Application Backend και Ui για συγχρονισμό και σωστή ενημέρωση αυτού.

Ακόμη δε κατά το event presense response όπου δείχνετε στην πάνω εικόνα να αποστέλλετε ολόκληρο το roster εφόσον το έχετε ενημερώσει εσωτερικά στο backend της εφαρμογής σας (πχ. σε μια in-memory database ή σε ένα object vatiable). Ακόμα θεμιτό είναι να μαζεύετε όσα περισσότερα status updates μπορείτε εάν σας νοιάζει το πάρε-δώσε μεταξύ ui και εφαρμογής. Ακόμη δε να έχετε στον νου σας ότι ένα participant στο roster μπορεί να είναι συνδεδεμένος σε πολλαπλές συσκευές και το status είναι ανά συσκευή.

Κατά την γνώμη μου είναι hacky ο παραπάνω τρόπος αλλά είναι η μόνη βιβλιοθήκη η οποία αναπτύσσετε προς το παρόν και συντηρείτε ενεργά (περίοδο που γράφετε το άρθρο). Αλλά λόγο ότι το API είναι βασικό και σπαρτιάτικο σε "μαθαίνει" xmpp
Advertisements

Εγκατάσταση και Ρύθμιση Node.js σε Windows10

Για τις ανάγκες ενός άλλου άρθρου που σκέφτομαι να ετοιμάσω χρειάζεται να εκτελέσω node.js αλλά όμως πέρα από το τυπικό installation χρειάζεται να εκτελέσω και κάποια έξτρα πραγματάκια προκειμένου να γίνει σωστή ρύθμιση για εγκατάσταση των εξαρτήσεων. Προτού όμως πάμε σε λεπτομέρειες θα πρέπει να εγκαταστήσετε την node.js από την κεντρική ιστοσελίδα. H διαδικασία είναι απλή και ουσιαστικά είναι next-next-next έτσι δεν νομίζω να αξίζει περαιτέρω ενέργειες.

Εφόσον το κάναμε εκτελούμε το cmd και δίνουμε την παρακάτω εντολή:

powershell -Command "Start-Process cmd -Verb RunAs"

Μετά στο NEO παράθυρο του command line δίνουμε την εντολή:

npm install -g windows-build-tools

Πλέον μπορείτε να αναπτύξετε οποιοδήποτε πρόγραμμα σε node.js ή να δοκιμάσετε έτοιμα προγράμματα από άλλα αποθετήρια κώδικα πχ.github.

Δημιουργία android εφαρμογών με ionic σε debian9

Στην αναζήτηση ενός ελευθέρου λογισμικού sdk (που επί το πλείστον είναι ελεύθερο αλλά έχει κάποια γ%^&*%^^& ιδιοταγή blobs) ήρθα σε αυτήν την σελίδα: https://wiki.debian.org/AndroidTools που ουσιαστικά είναι η προσπάθεια κάποιον ατόμων από την κοινότητα του debian να υπάρχει 100% ελεύθερο android sdk.

Προς τιμήν της προσπάθειας αυτής θα σας δείξω το πως να κάνετε εφαρμογές android με την χρήση του ionic framework και του 100% κελευθέρου android sdk. Ακόμη να σημειώσουμε ότι ο παρακάτω οδηγός λειτουργεί σε debian9 stable. (Όχι πως με την χρήση containers δεν μπορεί να τρέξει σε όποιο distro θες 😉 )

Κατ αρχάς θα πρέπει να εγκαταστήσουμε το πολυπόθητο ελέυθερο SDK:

  1. Εγκαταστήστε το με:sudo apt install android-sdk android-sdk-platform-23
  2. Εξάγετε την μεταβλητή περιβάλλοντος: export ANDROID_HOME=/usr/lib/android-sdk *

* Η εντολή αυτή μπορεί να μπει στο αρχείο ~/.bashrc για ποιο μόνιμες αλλαγές 😉

Εφόσον το εγκαταστήσαμε θα χρειαστεί να έχουμε το εκτελέσιμο npm:

  1. Πρώτα προσθέστε το αποθετήριο για μια ποιο πρόσφατη έκδοση του npm:
    curl -sL https://deb.nodesource.com/setup_6.x | sudo -E bash -
  2. Μετά εγκαταστήστε την nodejs (που εγκαθηστά και το npm):
    sudo apt-get install -y nodejs
  3. Ουκ ολίγες npm βιβλιοθήκες χρειάζοντε το παρακάτω πακέτο:
    sudo apt-get install -y build-essential

Μετά σύμφωνα με το site του ionic θα πρέπει να εκτελέσετε την παρακάτω εντολή (εάν δεν έχετε εγκατεστημένο το ionic framework):

npm install -g cordova ionic

Πλέον μεταβείτε στο κατάλογο του ionic project σας:

cd ^path του project σας^

Σε περίπτωση που δεν έχετε κάνει project δείτε στο http://ionicframework.com/getting-started/ για το πως θα κάνετε το δικό σας ionic project.

Όπως και να έχει θα πρέπει να ορίσετε σαν πλατφόρμα το android:

ionic cordova platform add android

Εφόσον το κάνετε θα πρέπει να προβείτε στις εξής ενέργειες:

  1. Μεταβείτε στο φάκελο platforms που είναι εντός του project σας
  2. Στο αρχείο AndroidManifest.xml ορίστε εκεί που λέει android:targetSdkVersion την τιμή 23
  3. Στα αρχεία project.properties και CordovaLib/project.properties ορίστε εκεί που λέει target την τιμή android-23

Πλέον μπορείτε να χτίσετε την εφαρμογή σας με την εντολή:

ionic cordova build android

Και ας αρχίσει το πάρτυ!!!!!!!!!!!

Εγκατάσταση Ionic Framework για ανάπτυξη υβριδικών mobile εφαρμογών σε Windows και Ubuntu GNU/Linux.

To ionic framework είναι ένα framework (σώπα σας είπα κάτι νέο) που συνδιάζει Angular.js και Apache cordova  προκειμένου μέσω javascript να μπορείς να δημιουργείς mobile εφαρμογές για IOS και Android.

Για να παίξει το εν λόγο framework θέλουμε την node.js, για windows την κατεβάζουμε από το https://nodejs.org/en/ και απλά πατάμε next next next ενώ σε Ubuntu linux δίνουμε:

sudo apt-get install nodejs npm

Μετά θα χρειαστούμε το git σε windows το κατεβάζουμε από την σελίδα http://www.git-scm.com/download/win ενώ σε linux δίνουμε στο τερματικό (Σε windows είναι σημαντικό να επιλέξετε να σας εγκαταστήσει και το bash κέλυφος (απλά πατήστε next next next) next next next):

sudo apt-get install git

Μετά σε windows ανοίγουμε το git-bash ενώ σε gnu/linux έχουμε ανοικτό το τερματικό μας.

Σημείωσεις:

  1. Σε Windows από εδώ και στο εξής οι εντολές θα τρέχουν από το git-bash.
  2. Σε Windows στις εντολές που αρχίζουν με sudo ΔΕΝ το βάζουμε.
    πχ. Η εντολή:

    sudo npm install -g ionic cordova

    Στο git-bash σε Windows θα την τρέξετε έτσι:

    npm install -g ionic cordova

Τώρα είτε στο terminal είτε στο git-bash δίνουμε τις εξής εντολή :

sudo npm install -g ionic cordova

Τώρα έχουμε 2 επιλογές:

  1. Να δημιουργήσουμε την δικιά μας εφαρμογή.
  2. Να συνεισφέρουμε στην ανάπτυξη ήδη υπάρχουσας εφαρμογής από το github.

Επιλογή 1:

Δίνουμε:

ionic start ^όνομα app^ tabs

Για το στυλ tabs του ionic:
Επιλογή για εγαρμογή με μενού στο κάτω μέρος της οθόνης
ή

ionic start ^όνομα app^ sidemenu

Για να δημιουργία του στυλ με πλαινό μενού του ionic:
Επιλογή για Εφαρμογή με Πλαϊνό μενού
(Δεν σας δείχνω την επιλογή bare διότι δεν βολεύει αν θέλετε να αρχίσετε μια νέα εφαρμογή η αν μαθένετε το framework)

Όπου ^ονομα app^ είναι πως θέλετε να ονομάσετε μια την εφαρμογή σας. Σας επισημαίνω ότι θα δημιουργηθεί ένας φάκελος στον τρέχων φάκελο που είστε στο τερματικό η στο git bash (που ουσιαστικά είναι το bash κέλυφος που χρησιμοποιεί το gnu/linux σε windows περιβάλλον)

Όταν μας ρωτήσει «Create an ionic.io account to send Push Notifications and use the Ionix View app» πορς το παρόν δίνουμε n. (Ειδάλλως y αν το χρειάζεστε για κάτι άλλο προσωπικά ΔΕΝ το έχω χρησιμοποιήσει.)

πχ. Αν δώσω την εντολή:

ionic start sample tabs

Θα δημιουργήσει τον φάκελο sample και θα βάλει μέσα σε αυτό τα κατάλληλα αρχεία για να δημιουργήσει ένα βασικό σκελετό εφαρμογής με tabs.

Θα το δούμε ότι δημιουργήθηκε ο φάκελος δίνοντας:

ls

Και εντοπίζοντας με το μάτι τον φάκελο που δημιουργήθηκε.

Μετά δίνουμε:

cd ^όνομα app^

Και μετά:

ionic serve

Για να το δοκιμάσετε στον browser σας. Αν πάτε πίσω στην κονσόλα (η στο git bash) και πατήσετε q και μετά enter θα κλείσει η «υποτυπώδης» web server που σας δείχνει την εφαρμογή.

Σημείωση: Η παραπάνω εντολή ενδεχομένως να σας βγάλει επιλογή δικτύου επιλέγουμε το 2 (localhost). Ακόμη
Τα windows θα σας βγάλει ένα μήνυμα για το εάν επιτρέπετε αυτήν την εφαρμογή να τρέχει στο δίκτυο όπου σαφώς λέμε ότι το επιτρέπουμε.

Για την Επιλογή 2:

Για την επιλογή αυτή θα υποθέσουμε ότι έχουμε ένα αποθετήριο στο github και θέλουμε να το κάνουμε clone.

Δημιουργούμε έναν φάκελο με την εντολή:

mkdir ^όνομα φακέλου^

Και μετά δίνουμε:

cd ^όνομα φακέλου^

Και μετά κάνουμε clone το github αποθετήριo:

git clone ^repo_name^ .

Σημείωση: μην ξέχάσετε την . στο τέλος.

Όπου ^όνομα φακέλου^ ένα χαρακτηριστικό όνομα για τον φάκελο που θα φιλοξενήσει το project.
Όπου ^repo_name^ copy paste από το github ή bitbucket. (Για github βλ. τα βελάκια στην παρακάτω εικόνα)
Αντιγραφή Αποθετηρίου από το github

Πχ. Πως να κατεβάσετε τον κώδικα του faster (μιας εφαρμογής που δημιουργήθηκε από στο #crownpolicy #transport hackathon):

Έστω τον φάκελο που θέλουμε να αποθηκεύσουμε την εφαρμογή ονομάζεται faster έτσι θα δώσουμε (είτε στο τερματικό του gnu/linux είτε στο git bash):

mkdir faster
cd faster
git clone git@github.com:kawai-developers/faster.git .

Και για να δούμε πως παίζει δίνουμε:

ionic serve