## Easy Port Testing
## ON SERVER:
dnf --assumeyes install nmap net-tools ; ## in case this has not yet been installed!
systemctl stop firewalld.service ; ## or make the particular port available!
ls -l | /usr/bin/ncat --listen 10000 ;
date | /usr/bin/ncat --listen 3030 ;
<
>
- https://www.cyberciti.biz/faq/unix-linux-check-if-port-is-in-use-command/
lsof -i -P -n | grep LISTEN ; ## make sure ports are listening
netstat -tulpn | grep LISTEN ; ## another way to make sure ports are listening
## ON CLIENT:
just type cmd, and enter ‘telnet’ – this may be necessary: Enable telnet on windows-11 and REBOOT — 2024-10-01
telnet 123.123.123.123 10000 ; ## should give us the directory (or date) and then the ncat command on the server STOPS
- NOTICE ONLY ONE SPACE BETWEEN IP ## and PORT ### !! (this might just be a m$ thing)
## working fake webserver test:
https://jameshfisher.com/2018/12/31/how-to-make-a-webserver-with-netcat-nc/
these did NOT work for me:
(this one requires ‘screen’ whatever that is)
https://support.cpanel.net/hc/en-us/articles/4403282341143-How-to-use-ncat-netcat-as-a-mini-webserver-to-diagnose-network-connectivity-related-issues
https://stackoverflow.com/questions/16640054/minimal-web-server-using-netcat
settings (but not working quite yet)
185.242.5.91 (185.242.5.90 / Protocol: TCP / OpenVpn Port: 443 / OpenConnect Port: 22)
Mark (185.242.5.91 / Protocol: UDP / OpenVpn Port: 443 / OpenConnect Port: 22)
Instructions to run feathers completely from console, no coding!
IMPORTANT: open up a new tab “about:blank”
Click to open a new
about:blank page.
Load the libraries
/* load in libraries */
[ 'https://cdnjs.cloudflare.com/ajax/libs/socket.io/2.0.4/socket.io.js'
, 'https://unpkg.com/@feathersjs/client@^3.0.0/dist/feathers.js'
].forEach( (src) => {
let script = document.createElement('script');
// script.setAttribute('crossOrigin', 'anonymous' ); /* optional */
script.src = src;
// script.type = 'javascript'; /*optional */
script.src = src;
script.async = false;
document.head.appendChild(script); // or document.getElementsByTagName('script')[0];
});
alternative method:
/usr/bin/cat <<END | ncat --listen 80 ;
<!DOCTYPE html>
<html lang="en-us">
<head>
<script src='https://cdnjs.cloudflare.com/ajax/libs/socket.io/2.0.4/socket.io.js'></script>
<script src='https://unpkg.com/@feathersjs/client@^3.0.0/dist/feathers.js'></script>
</head>
<body>
fake webserver page. include extra jScript code in the console.
</body>
</html>
END
initialize constants
/* initialize constants */
const app = feathers();
const socket = io(); /* defaults to: const socket = io('ws://localhost:3030'); */
const socket = io('ws://###.###.###.###:3030'); /*if we need to connect to different host */
app.configure(feathers.socketio(socket)); /* PLEASE dont skip this one!! */
/* -- or -- */
app.configure(feathers.socketio(io('ws://###.###.###.###:3030'))); /* just combine the last two lines */
create(POST)
/* create(
POST) */
async function createTiny(name, address) {
let createResult
= await app.service(‘tiny-connect’).create({ name: name, address: address });
console.log(‘createTiny function result: ‘ + JSON.stringify(createResult) );
return createResult;
};
createTiny(‘Mark Edwards’, ’123 Swallow Lane’).then((value) => { /* create(POST) */
console.log(‘createTiny: ‘ + JSON.stringify(value));
})
get(GET) just one using the primary index
/* get(GET) (just one by index) */
async function getTiny(id) { return await app.service(‘tiny-connect’).get(id); };
—- or —-
async function getTiny(id) {
let getResult = await app.service(‘tiny-connect’).get(id);
console.log(‘getTiny function: ‘ + JSON.stringify(getResult) );
return getResult;
};
let getTinyResult = null; let key = 1; // assuming your row ID is one
getTiny(key).then( value => { /* get(GET) */
getTinyResult = value;
console.log(‘getTiny(’ + key + ‘) : ‘ + JSON.stringify(getTinyResult) );
});
/* one line test: */
(async () => { try { let result = await app.service(‘stimword’).get(1) ; console.log(‘the result is: ‘ + JSON.stringify(result)) } catch (e) { console.log(e); } } )() ;
/* or: */
(async () => { let logoutResult = await app.service(‘stimword’).get(2); console.log(logoutResult); })().catch(e => { console.log(e) });
find(GET) all or by query
/* find(GET) (get all or by query) */
async function findTiny(query) {
return await app.service(‘tiny-connect’).find(query);
};
async function findTiny(query) {
console.log(‘Query function using: ‘ + JSON.stringify(query) );
let findResult = await app.service(‘tiny-connect’).find(query);
console.log(‘findTiny function: ‘ + JSON.stringify(findResult) );
return findResult;
};
let findTinyResultAll;
findTiny(null).then((value) => { /* find(GET) (find all) */
findTinyResultAll = value;
console.log(‘findTiny without query: ‘ + JSON.stringify(findTinyResultAll) );
});
let findTinyResultOne; let findDataObject = { ‘query’ :{ id: 0}}; // again, assuming your id is zero!
findTiny(findDataObject).then((value) => { /* find(GET) (with data ) */
findTinyResultOne = value;
console.log(‘findTiny with query: ‘ + JSON.stringify(findTinyResultOne) );
});
/* shortcut examples: */
(async () => { try { let result = await app.service(‘stimword’).find() ; console.log(‘the result is: ‘ + JSON.stringify(result)) } catch (e) { console.log(e); } } ) () ;
(async () => { try { let result = await app.service(‘stimword’).find({‘query’:{‘stimwordWord’:‘horse’}}) ; console.log(‘the result is: ‘ + JSON.stringify(result)) } catch (e) { console.log(e); } } ) () ;
Accessing a KNEX RAW selecxt
SELECT JSON_ARRAYAGG(
JSON_OBJECT(
..........
)
) 'JSON_ARRAYAGG'
.....................................
const result = await knex.raw( sqlStatement, sqlQuery);
return result[0][0].JSON_ARRAYAGG ;
...................................
var newResult;
(async () => { try { let result = await app.service('raw-service').find({query: sqlQuery}) ; newResult = result; } catch (e) { console.log(e); } } )() ;
console.log(JSON.parse(newResult));
patch(PATCH) to update row(s)
/* patch(PATCH) */
async function patchTiny(id, data, params) { /* patch(PATCH) */
let patchResult = await app.service(‘tiny-connect’).patch(id, data, params);
console.log(‘patchTiny function: ‘ + JSON.stringify(patchResult) );
return patchResult;
};
let patchResult = null; let patchKey = 0; let patchData = {address: ’5678 There Street!’ };
patchTiny(patchKey, patchData ).then( value => { /* patch(PATCH) */
patchResult = value;
console.log(‘patchResult: ‘ + JSON.stringify(patchResult));
});
combine create and insert into one promise
async function clientMasterCreate(query) {
return await app.service(‘client-master’).create(query);
};
async function clientMasterFind(query) {
return await app.service(‘client-master’).find( { ‘query’ : query } );
};
clientMasterObj = { ‘layoutName’ : ‘PESL’
, ‘teacherEmail’ : ‘info@englishwithoutaccent.com’
, ‘teacherAutoIncr’ : 385
, ‘clientMasterEmail’ : ‘12yukos@gmail.comX’
};
clientMasterFind(clientMasterObj)
.then( (clientMasterRow) => {
return clientMasterRow
})
.then( (clientMasterRow) => {
if ( clientMasterRow.data.length == 0 ) {
return clientMasterCreate(clientMasterObj)
.then( (clientMasterRow) => {
console.log(‘inserting: ‘ + clientMasterRow.clientMasterAutoIncr );
return clientMasterRow.clientMasterAutoIncr;
})
} else {
return clientMasterRow.data[clientMasterRow.data.length-1].clientMasterAutoIncr;
}
})
.then ((result) => {
console.log(‘clientMasterAutoIncr: ‘ + result)
});
1 – Initialization
latest RH node instructions
older instructions
Install Node version 16 or greater:
dnf module enable nodejs:20 ; ## installing version 20 in this example.
dnf module list nodejs ; ## optional step!
dnf install nodejs ;
node --version ;
npm --version ;
install the feathers command-line interpreter (CLI):
npm install -g feathersjs/cli ; ### or --global
npm install
feathersjs/cli -g ; ### for generating apps (notice g trails…. i think only this one actually works!
npm install feathersjs/cli
4.8.0 —global ; ## 2023-04-19 install a SPECIFIC VERSION!
npm install @feathersjs/feathers —save ; ## save is no longer needed
##https://stackoverflow.com/questions/19578796/what-is-the-save-option-for-npm-install
export PATH=$PATH:/usr/local/bin/ ; ## 2024-09-24 — this was required!
which feathers ; ##
feathersjs —version ; ##
Optionally disable or modify the firewall
systemctl stop firewalld; ## or just authorize port 3030
## --or---
firewall-cmd --add-port=3030/tcp ;.
## --- or----
firewall-cmd --add-port=3030/tcp --permanent ;
Generate an app using the CLI
feathers generate app ; ## notice that NO npm install's are used
npx feathers generate ; ## apparently another method (2024-09-24
feathers generate service ;
## select 'knex' or 'objection' (see below)
### connection string should look like this: "mysql://knexUser:knexPassword@localhost:3306/comptonTransAnlys"
DEBUG=* npm start ; ## test that app starts successfully, optional DEBUG
DEBUG=knex:query npm start ;
2 – modify this files
./config/default.js
"paginate": {
"default": 0,
"max": 0
3a – modify these files for KNEX
./src/services/tester/tester.class.js – KNEX
super({
...options,
name: 'tableName' /* changed this name to reflect the ACTUAL table name */
, id: 'tableNameAutoIncr' /* added this line to reflect the primary key */
});
./src/models/tester.model.js – KNEX
module.exports = function (app) {
return app.get('knexClient'); /* this is MUCH shorter than original! */
};
3b – modify these files for OBJECTION
./src/services/tester/tester.class.js – OBJECTION
add actual table name and unique id column name
model: Model
, 'name' : 'marksTestTable' , 'id' : 'marksTestTableAutoIncr' // line added by mark!!
./src/models/tester.model.js – OBJECTION
line 8: [specify
REAL table name]
static get tableName() {
return 'marksTestTable'; // make SURE table name is correct !! (had to remove underscores)
}
line 14 old: [specify column names in array]
required: ['text'],
line 17 new:
required: ['columnOne', 'columnTwo'], /* original: required: ['text'], */
line 17 old: [specify column types {type: ‘string’ } { type: ‘number’ } { type: ‘timestamp’} ]
text: { type: 'string' }
line 17 new:
'columnOne': { type: 'string' } , 'columnTwo': { type: 'number' } /* original: text: { type: 'string' } */
see: https://knexjs.org/guide/schema-builder.html#date
line 22: comment out lines: ( or add
.slice(0, 19).replace(‘T’, ‘ ‘); to dates.)
$beforeInsert() {
/* original: this.createdAt = this.updatedAt = new Date().toISOString(); */
// or possibly add this:
this.createdAt = this.updatedAt = new Date().toISOString().slice(0, 19).replace(‘T’, ‘ ‘);
$beforeUpdate() {
/* original: this.updatedAt = new Date().toISOString(); */
// or possibly add this:
this.updatedAt = new Date().toISOString().slice(0, 19).replace(‘T’, ‘ ‘);
per https://stackoverflow.com/questions/5129624/convert-js-date-time-to-mysql-datetime
line 35: [ eliminate the ‘create table’ stuff ]
/* most likely db.schema.createTable can be SKIPPED unless a table actually needs to be created this way! */
const db = app.get('knex');
db.schema.hasTable('marksTestTable').then(exists => {
if (!exists) {
console.error('table marksTestTable missing!');
/*
db.schema.createTable('shit', table => {
table.increments('id');
table.string('text');
table.timestamp('createdAt');
table.timestamp('updatedAt');
})
*/
.then(() => console.log('Created shit table')) // eslint-disable-line no-console
.catch(e => console.error('Error creating shit table', e)); // eslint-disable-line no-console
}
})
.catch(e => console.error('Error creating shit table', e)); // eslint-disable-line no-console
it should
ONLY contain:
module.exports = function (app) {
return [class name];
}
4 – Start the app
DEBUG=knex:query npm start ; ## run the app, optional DEBUG
DEBUG=* npm start ; ## run the app, optional DEBUG
5 -Test the app
DONT USE “PUT”, USE “PATCH” INSTEAD!
Postman: Body—->x-www-form-url-urlencoded to POST (create)
POST: http://192.168.123.220:3030/teachers?lastName=Edwards&firstName=Lori (create)
PATCH: http://192.168.123.220:3030/teachers/2/?firstName=Marky (patch)
POST – http://192.168.123.220:3030/tester?columnOne=Column One Value&columnTwo=Column Two Value (add new value)
GET – http://192.168.123.220:3030/tester/1/ ( get by primary id)
GET – http://192.168.123.220:3030/tester/?columnOne=column One Value (find by column value)
GET (find) – be sure “Body—>xx-www-form-urlencode” is blank
GET (get) – be sure “Params” is blank
PATCH – be SURE “Params” is blank, only use “Body—>xx-www-form-urlencode”
## a complicated one!
http://192.168.123.220:3030/tester/
? testerAutoIncr=1
& $select[]=columnTwo
& $select[]=columnOne
& $sort[columnOne]=-1
## will produce:
## select `columnTwo`, `columnOne`, `tester`.`testerAutoIncr` from `tester` where `testerAutoIncr` = ? order by `columnOne`
## https://stackoverflow.com/questions/11889997/how-to-send-an-array-in-url-request/11890080#11890080
## ? col = val1 & col = val2 & col = val3
## will produce:
## WHERE col= ‘val1’ OR col=‘val2’ OR col=‘val3’
### reference: https://dove.feathersjs.com/api/databases/querying.html#select
6 – Create a “before” hook to manipulate the SELECT statement.
feathers “before” hook: [i think that is required by Objection]
./src/hooks/tester.js
// Use this hook to manipulate incoming or outgoing data.
// For more information on hooks see: http://docs.feathersjs.com/api/hooks.html
// eslint-disable-next-line no-unused-vars
module.exports = (options = {}) => {
return async context => {
context.params.query = { // added by mark
…context.params.query, // added by mark
$select: [‘columnTwo’,‘columnOne’], // added by mark
$sort: { ‘columnOne’ : 1 } // added by mark
} // added by mark
return context;
};
};
or: (much better:) https://knexjs.org/guide/query-builder.html
module.exports = (options = {}) => {
return async context => {
const query = context.service.createQuery(context.params) ;
// https://knexjs.org/guide/query-builder.html#knex
query .clear(‘select’) // remove ALL existing columns from queryBuilder
.select({ ‘languageNormsName’ : ‘languageNormsName’ } )
// or just .select(‘languageNormsName’)
.distinct()
.orderBy(‘languageNormsName’)
;
context.params.knex = query ;
return context;
};
};
[i think this is required for knex (not objection]
// https://feathersjs.com/api/databases/knex.html#createquery-params
// https://knexjs.org/guide/query-builder.html#clear
// https://stackoverflow.com/questions/47263583/how-can-i-retrieve-unique-values-from-a-column-with-knex-js
/* old fashioned way to clear select statements, use ` .clear('select') ` instead!
for ( index in query._statements.filter ( val => val['grouping'] === 'columns' ) )
{ query._statements.splice(index,1) // remove the "default" column selection
} ;
*/
==========================================================
#####################npm init —yes ;
################npm install @feathersjs/feathers —save ;
######### ???????? npm install knex —save ;
############npm install feathers-knex —save ;
problem: jfbmusic.comptonpesltrainers.com forwards to an error page
solution:
1) turn OFF vpn
2) cache flush