I have pdfs with compressed data that qpdf decompresses and saves as a decompressed readable pdf. But I would like to make a node javascript-only solution that I can package up so my users don’t have to install qpdf. There are a lot of javascript npm libraries, but none of them seem to have the same simple “open with uncompress and save” functionality of qpdf. Is this do-able with javascript only?
Category: javascript
Category Added in a WPeMatico Campaign
How to find patterns in image in js
I am new to AI and text recognition from an image world, I am trying to recognition characters patterns from an image using javascript, but I have absolutely no idea where to even start. My goal is to recognize characters of this format: 000-00-000 or 00-000-00. inside of images (license plates). Can someone please refrence me to resources where I can find this information or tell me about certine libraries that does that?
select2 – removing a js inserted item keeps it as an option
i have a standard select2 setup
<div class="form-group">
<label for="cities">Enter Cities</label>
<div>
<select class="form-control cities-tags" multiple="multiple"></select>
<button type="button" id="import-cities" data-bs-toggle="modal" data-bs-target="#importModal">
<svg>...</svg>
</button>
</div>
</div>
apply select 2
$(".cities-tags").select2({
tags: true,
})
i also have a model to paste a comma separated values as text, and it will split them into separate tags and input them.
// #importCitiesBtn is a button in the model to confirm pasting
$('#importCitiesBtn').on('click', function() {
var importedCities = $('#importCitiesInput').val().split(',');
importedCities.forEach(function(cityName) {
if (cityName.trim() == '') {
return;
}
let option = $('.cities-tags').find("option:contains('" + cityName.trim() + "')");
if (option.length === 0) {
var newOption = new Option(cityName.trim(), cityName.trim(), true, true);
$('.cities-tags').append(newOption).trigger('change');
} else {
$('.cities-tags').val(cityName.trim()).trigger('change');
}
});
});
the js insertion works fine, here is the problem:
when i insert cities manually and remove them(click the x), they are completely removed (good)
when i remove a js inserted item, its removed from the selected items but an option is still present (bad)
expected behavior: when i remove an item wither added manually or by js, it has no trace or its option is also removed from the list.
note: extra points if you can write logic to paste the comma separated string directly into the select and have it automatically parse and append.
How do I parameterize a mySQL query so that the server selects from the database based off user input with nodejs?
I have set up a simple local server that is connected to a mySQL database and it connects to the client and queries work but I need the query to work with a variable received from the client.
This is the server:
app.get('/data', async(req, res) => {
var depart = req.query.dep;
if (!depart) {
return res.status(400).json({ error: 'Missing department parameter' });
}
var existsQuery = 'SELECT * FROM db.table WHERE department = ?';
db.query(existsQuery, [depart], (err, result) => {
if (err) throw err;
console.log("result", result);
res.json(result)
});
});
The console log just prints [] instead of results from the database. Putting the query with a defined department number into mySQL gives results so I know that there are actual results that the server can get.
Redux state change does not rerender the component based on logic
I have a react app (vite) with Redux for global state management. I have a global state called auth of boolean in Redux store and it is updated through dispatcher when the user correctly signs up to the app or signs in to the app. I can see this state change is happening in the Redux dev tools. But the component Home is supposed to be rendered when the state of this auth is true. But it does not. I new to Redux and don’t have much experience. Can anybody help me resolve or debug this issue, I don’t know how to go about debugging this. I have attached the relevant code snippets. Thanks.
main
ReactDOM.render(
<ErrorBoundary>
<Provider store={store}>
<Routes />
</Provider>
</ErrorBoundary>,
document.getElementById('root')
);
Routes
export default function Routes() {
return (
<Router>
<Switch>
<Route exact path='/' component={App} />
<Route path='/login' component={Signin} />
<Route path='/register' component={Signup} />
</Switch>
</Router>
);
}
App
export default function App() {
return <PrivateRoute component={Home} />
}
PrivateRoute
export default function PrivateRoute({ component: Component, ...rest }) {
const authenticated = useAppSelector((state) => state.auth.isLogged);
return (
<Route
{...rest}
render={(props) =>
authenticated ? <Component {...props} /> : <Redirect to={'/login'} />
}
/>
);
}
Signin
const Signin = () => {
const [state, handlers] = useSignin();
return (
<SigninUI {...state} {...handlers} />
)
}
export default Signin;
Signin handler
const useSignin = (): [SigninState, SigninHandlers] => {
const dispatch = useAppDispatch();
const handleSubmit: SigninHandlers["handleSubmit"] = (e) => {
e.preventDefault();
apis.signin(state.email, state.pwd)
.then((data) => {
setState((prevState) => ({ ...prevState, errorMsg: "", successMsg: data.data.message }));
dispatch(authActions.login())
})
.catch((e) => {
setState((prevState) => ({ ...prevState, successMsg: "", errorMsg: e.data.message }));
})
}
return [state, { handleEmailChange, handlePwdChange, handleSubmit }]
}
useAppSelector, useAppDispatch
export const useAppDispatch = useDispatch.withTypes<AppDispatch>();
export const useAppSelector = useSelector.withTypes<RootState>();
store
export const store = configureStore({
reducer: {
auth: authReducer,
},
});
export type RootState = ReturnType<typeof store.getState>;
export type AppDispatch = typeof store.dispatch;
authReducer
const initialState: AuthState = {
isLogged: false,
};
const authSlice = createSlice({
name: "auth",
initialState,
reducers: {
login: (state) => {
state.isLogged = true;
},
logout: (state) => {
state.isLogged = false;
},
},
});
export const authActions = authSlice.actions;
export const authReducer = authSlice.reducer;
Google font not loading in storybook
I have followed the document and other answers on stackoverflow and github, as well as reading the storybook documentation.
I have react storybook and want to import Manrope font. As per the instruction I have created a preview-head.html file inside my .storybook folder and I have the code as following.
<link rel="preload" href="https://fonts.googleapis.com/css2?family=Manrope:wght@400;500;600;700;800" />
<!-- Or you can load custom head-tag JavaScript: -->
<script src="https://use.typekit.net/xxxyyy.js"></script>
<script>try{ Typekit.load(); } catch(e){ }</script>
However, when I use it in my styled-components it doesn’t get picked up.
export const Initials = styled.div`
color: ${color.midnightBlue};
font-family: Manrope;
font-size: 24px;
width: 100%;
padding: 0px 33px;
font-weight: ${typography.weight.extrabold}; //800
`;
Am i missing some configuration? Do I need to add some loader?
For reference, this is what my preview.js file looks like:
/** @type { import('@storybook/react').Preview } */
const preview = {
decorators: [
(Story) => (
<>
<Story />
</>
),
],
parameters: {
actions: { argTypesRegex: '^on[A-Z].*' },
controls: {
matchers: {
color: /(background|color)$/i,
date: /Date$/,
},
},
},
};
export default preview;
Disable source file path comment in esbuild output
When I build my JS with esbuild.build(options) the original source file path is included as a comment in the output file beginning. How do i avaoid it?
// C:/Users/ragha/AppData/Local/Temp/stash-creator/index.jsx
(async () => {
await app_default();
})();
Import Nuxt3 utility function into Netlify Edge Function
How can I import a utility function from the utils directory into my edge function in Nuxt3?
If I have a function sum in /utils/sum.js
export const sum = (…nums) => nums.reduce((prev, current) => prev + current)
And an edge function in netlify/edge-functions/foo.js
const result = sum(1, 2, 3)
export default () => {
return Response.json({ sum: result })
}
export const config = {
path: '/foo'
}
This breaks and sum is not defined. I am able to import bare modules into the edge function but I can‘t import my own utility functions.
Slider in desktop mode and toggle in mobile mode
I would like to do the following:
-add two destinations: Barcelona and Madrid in the same line (table with 2 columns 1 row ) that is responsible in mobile mode
On desktop mode:
-when I click one of the destinations, the tours list for that specific destination should be shown below the image, if I click on the second destination, should close the first destinations tours and show the second clicked destination tours below the image
[image1] | [image2]
(tours list 1 / tours list 2)
On mobile mode:
-the first list of tours (Barcelona) should appear between the two destinations, the second
after the second destination
[image1]
(tours list 1)
[image2]
(tours list 2)
How can I do that? The design also has some problems.
Thanks
$(function() {
$('.showSingle').click(function() {
$('.targetDiv').not('#div' + $(this).attr('target')).hide('slow');
$('#div' + $(this).attr('target')).toggle('slow');
});
});
.showSingle, targetDiv
{
padding-top:20px;
padding-right:20px;
padding-bottom:20px;
}
.showSingle img, targetDiv
{
border:5px solid white;
}
.nrtours_destinations
{
position:absolute;
color:#333;
background-color:white;
font-size:1.2em;
width: 70px;
/*margin-left:auto;
margin-right:auto;*/
margin-left:225px;
padding-left:3px;
top: 40px;
}
.barcelona_destinations,
.madrid_destinations
{
position:absolute;
color:#333;
background-color:white;
font-size:4em;
width: 300px;
margin-left:auto;
margin-right:auto;
top: 235px;
text-align: center;
padding-top:16px;
height:60px;
opacity:0.8;
cursor:hand;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.7.1/jquery.min.js"></script>
<div class="buttons">
<a class="showSingle" target="1">
<span class="barcelona_destinations">Barcelona</span><span class="nrtours_destinations">3 Tours</span><img src="https://artistatours.com/wp-content/uploads/2022/07/pexels-enrico-perini-819764-636x636.jpeg" class="destination-img" alt="El Tour Más Completo de Barcelona" width="300px">
</a>
<a class="showSingle" target="2">
<span class="madrid_destinations">Madrid</span><span class="nrtours_destinations">1 Tour</span><img src="https://artistatours.com/wp-content/uploads/2024/01/madrid-385104_1280-636x636.jpg" class="destination-img" alt="¡Madrid al Completo!(Con actores)" width="300px">
</a>
</div>
<span style="clear:both;"><span>
<div id="div1" class="targetDiv" style="display:none;">Barcelona Tours</div>
<div id="div2" class="targetDiv" style="display:none;">Madrid Tours</div>
</div>
TableVirtuoso displays only one row when ‘data-index’ is missing from row props
Using TableVirtuoso I encountered a problem where only a single row of data was displayed. This was despite mostly copying the MUI example from their website.
I only changed the row component, row content rendering and row header rendering.
const VirtuosoTableComponents: TableComponents<Data> = {
Scroller: React.forwardRef<HTMLDivElement>((props, ref) => (
<TableContainer component={Paper} {...props} ref={ref} />
)),
Table: (props) => (
<Table {...props} sx={{ borderCollapse: 'separate', tableLayout: 'fixed' }} />
),
TableHead,
TableRow: ({ item: _item, 'data-index': index, ...props }) => <TableRow onClick={onRowClick(index)} {...props} />,
TableBody: React.forwardRef<HTMLTableSectionElement>((props, ref) => (
<TableBody {...props} ref={ref} />
)),
};
export default function ReactVirtualizedTable() {
return (
<Paper style={{ height: 400, width: '100%' }}>
<TableVirtuoso
data={rows}
components={VirtuosoTableComponents}
fixedHeaderContent={fixedHeaderContent}
itemContent={rowContent}
/>
</Paper>
);
}
Keep the object in the 3D space even when the camera is not focusing the marker
When the entity spawns on the marker and I move the camera around, the entity disappears. However, I want the entity to spawn once when the camera focuses on the marker and to remain visible even when the camera loses focus. Reference
<!DOCTYPE html>
<html>
<script src="https://aframe.io/releases/1.3.0/aframe.min.js"></script>
<!-- we import arjs version without NFT but with marker + location based support -->
<script src="https://raw.githack.com/AR-js-org/AR.js/dev/aframe/build/aframe-ar.js"></script>
<body style="margin : 0px; overflow: hidden;">
<a-scene embedded arjs>
<a-marker preset="hiro">
<a-entity
position="0 0 0"
rotation="0 0 0"
scale="0.05 0.05 0.05"
gltf-model="../image-tracking/nft/trex/scene.gltf"
></a-entity>
</a-marker>
<a-entity camera></a-entity>
</a-scene>
</body>
</html>
New to this, I’m trying to create a chatbot using openai api
So I’m new to coding and I’m trying to figure out why I keep getting a 500 error from this code and how I can fix it. Essentially I’m trying to build a chatbot using express and handlebars. I have the frontend set up but I am trying the show the ai response in a chatbox. According to the console the error is in my server-side code any help would be greatly appreciated
const express = require('express');
const router = express.Router();
const { OpenAI } = require('openai');
// Load your OpenAI API key from environment variables
require('dotenv').config();
const openai = new OpenAI({ apiKey: process.env.OPENAI_API_KEY });
// POST route to handle chat requests
router.post('/', async (req, res) => {
// Extract user input, chat history, and personality from the request body
const { userInput, chatHistory, personality } = req.body;
/* Build the message list for the OpenAI API, including the personality if provided
let messageList = chatHistory.map(msg => ({
role: msg.role,
content: msg.content
}));
if (personality) {
messageList.unshift({ role: "system", content: `You are ${personality}.` });
}*/
// Add the user's input to the message list
messageList.push({ role: "user", content: userInput });
try {
// Call the OpenAI API using the chat completions method
const response = await openai.chat.completions.create({
messages: [
{
role: "system",
content: `Respond to me as if you are ${personality}.`,
},
],
model: "gpt-3.5-turbo-1106",
});
// Extract and send the AI's response
const aiResponse = completion.choices[0].message.content;
res.json({ aiResponse, chatHistory: [...chatHistory, { role: "user", content: userInput, aiResponse }] });
} catch (error) {
// Handle any errors from the API call
console.error("Error calling OpenAI:", error);
res.status(500).send(error.message);
}
});
// Export the router so it can be used in your main server file
module.exports = router;
here is the code frontend js
document.addEventListener('DOMContentLoaded', () => {
const sendButton = document.getElementById('send-button');
const userInputField = document.getElementById('user-input');
const personalitySelect = document.getElementById('personality-select');
const chatBox = document.getElementById('chat-box');
let chatHistory = [];
sendButton.addEventListener('click', () => {
const message = userInputField.value;
const personality = personalitySelect.value;
if (message.trim()) {
sendMessageToServer(message, personality);
userInputField.value = '';
}
});
function sendMessageToServer(message, personality) {
chatHistory.push({ role: 'user', content: message });
limitChatHistory();
fetch('/api/chat', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify({ userInput: message, chatHistory, personality }),
})
.then(response => response.json())
.then(data => {
updateChatBox('You', message);
updateChatBox(personality, data.aiResponse);
chatHistory.push({ role: personality, content: data.aiResponse });
limitChatHistory();
})
.catch(error => {
console.error('Chat Error:', error);
});
}
function updateChatBox(sender, message) {
const messageElement = document.createElement('div');
messageElement.textContent = `${sender}: ${message}`;
chatBox.appendChild(messageElement);
chatBox.scrollTop = chatBox.scrollHeight; // Auto-scroll to the latest message
}
function limitChatHistory() {
if (chatHistory.length > 4) {
chatHistory = chatHistory.slice(-4);
}
}
});
I tried to edit the backend code according to the api documentation but I can’t seem to get it to display in a chatbox .I am able to get this to run as a node application but I can’t seem to get it to render in the browser
await fetch does not seem to wait
I have some code calling to load the same template really fast. I’ve tried to implement a simple caching system to only fetch when the template wasn’t previously loaded, but I can’t seem to get the await to truly wait until the function is completed.
The code for the template loading system:
var arrContent = []; //array of objects: {"url":"http://...", "content": "<div>..."}
var content = null;
this.loadFile = async function(url){
//Check if the content was already loaded
let i = findContentIndex(url);
if(i != null){ // The template already exist, simply load it from memory
console.log("Cached!");
content = arrContent[i].content;
}else{
//Content is not already in cache, load it from the url
console.log("Fetching...");
await fetch(url)
.then(function(response){
return response.text();
})
.then(function(response) {
content = response;
arrContent.push({"url": url, "content": content});
})
.catch(
function() {
error => console.log(error);
}
);
console.log("content");
}
}
function findContentIndex(url){
for(let i=0; i<arrContent.length; i++)
if(arrContent[i].url != undefined && arrContent[i].url == url)
return i;
return null;
}
this.render = function(){
//...
}
What I end up is with an array containing many duplicate of the same template URL, where as the code should prevent duplicate from happening.
For context, the calls are made this way. Multiple calls within a few ms of each others:
await Tpl.loadFile(chrome.runtime.getURL("view/widget.html"));
let content = Tpl.render();
The output will look something like:
Fetching...
Fetching...
Fetching...
Fetching...
Fetching...
content
content
content
content
content
Instead of:
Fetching...
content
Cached!
Cached!
Cached!
Cached!
If I could have the entire LoadFile function executed just once at the time it would solve my problem.
Thank you !
DevExtreme React – position of $ character changes from end of string to start
For some reason the “~!#%$$”:“ symbols appear in the start of the text property of CheckBox component even if I add them in the end of the string when rtlEnabled is on.
I assume that the purpose of rtlEnabled is to switch positions of the checkbox and the label, not the composition of the string.
I’ve tried to track the problem but without any luck yet…
It can be reproduced easily from here
edit the code from the example like this

the result is this: &test, instead of test&
Webrtc client peer connection state goes to fail after a few seconds of inactivity
javascript code:
// peer connection
var pc = null;
var total_clients_audio = 0;
var total_clients_video = 0;
var have_server_video = false;
var have_server_audio = false;
var local_call_number = null;
var clients_pc = [];
var closing = false
var controller = null;
var signal;
var local_stream = {"audio":null,"video":null};
var stream_client_1 = {"audio":null,"video":null};
var stream_client_2 = {"audio":null,"video":null};
var stream_client_3 = {"audio":null,"video":null};
function createLocalPeerConnection(client_call_number,client_name,client_surname){
var config = {
sdpSemantics: 'unified-plan',
iceServers: [{urls: ["stun:stun1.l.google.com:19302","stun:stun2.l.google.com:19302","stun:stun.l.google.com:19302","stun:stun3.l.google.com:19302","stun:stun4.l.google.com:19302"]}]
};
clients_pc.push(new RTCPeerConnection(config));
clients_pc[clients_pc.length-1].addEventListener('track', function(evt) {
console.log(client_call_number);
if (evt.track.kind == 'audio'){
if (local_call_number == 1){
if (client_call_number == 2){
document.getElementById('client-audio-2').srcObject = evt.streams[0];
stream_client_2.audio = evt.streams[0];
}else if (client_call_number == 3){
document.getElementById('client-audio-3').srcObject = evt.streams[0];
stream_client_3.audio = evt.streams[0];
}
}else if (local_call_number == 2){
if (client_call_number == 1){
document.getElementById('client-audio-2').srcObject = evt.streams[0];
stream_client_2.audio = evt.streams[0];
}else if (client_call_number == 3){
document.getElementById('client-audio-3').srcObject = evt.streams[0];
stream_client_3.audio = evt.streams[0];
}
}else{
if (client_call_number == 1){
document.getElementById('client-audio-2').srcObject = evt.streams[0];
stream_client_2.audio = evt.streams[0];
}else if (client_call_number == 2){
document.getElementById('client-audio-3').srcObject = evt.streams[0];
stream_client_3.audio = evt.streams[0];
}
}
}else{
if (local_call_number == 1){
if (client_call_number == 2){
document.getElementById('client-video-2').srcObject = evt.streams[0];
stream_client_2.video = evt.streams[0];
}else if (client_call_number == 3){
document.getElementById('client-video-3').srcObject = evt.streams[0];
stream_client_3.video = evt.streams[0];
}
}else if (local_call_number == 2){
if (client_call_number == 1){
document.getElementById('client-video-2').srcObject = evt.streams[0];
stream_client_2.video = evt.streams[0];
}else if (client_call_number == 3){
document.getElementById('client-video-3').srcObject = evt.streams[0];
stream_client_3.video = evt.streams[0];
}
}else{
if (client_call_number == 1){
document.getElementById('client-video-2').srcObject = evt.streams[0];
stream_client_2.video = evt.streams[0];
}else if (client_call_number == 2){
document.getElementById('client-video-3').srcObject = evt.streams[0];
stream_client_3.video = evt.streams[0];
}
}
}
});
return clients_pc[clients_pc.length-1];
}
function createPeerConnection() {
var config = {
sdpSemantics: 'unified-plan',
iceServers: [{urls: ['stun:stun.l.google.com:19302']}]
};
pc = new RTCPeerConnection(config);
//pc = new RTCPeerConnection();
// connect audio
pc.addEventListener('track', function(evt) {
console.log("track");
console.log(evt.streams[0].getTracks());
//alert(pc.getTransceivers().length);
if (evt.track.kind == 'audio'){
$("#signal-audio").trigger("pause");
$("#signal-audio").currentTime = 0; // Reset time
document.getElementById('server-audio').srcObject = evt.streams[0];
$("#control_call_button").addClass("d-none")
$("#stop_call_button").removeClass("d-none")
}else if (evt.track.kind == 'video'){
document.getElementById('server-video').srcObject = evt.streams[0];
}
});
return pc;
}
function timeoutPromise(ms, promise) {
return new Promise((resolve, reject) => {
const timeoutId = setTimeout(() => {
reject(new Error("promise timeout"))
}, ms);
promise.then(
(res) => {
clearTimeout(timeoutId);
resolve(res);
},
(err) => {
clearTimeout(timeoutId);
reject(err);
}
);
})
}
function negotiate() {
return pc.createOffer({"offerToReceiveAudio":true,"offerToReceiveVideo":true}).then(function(offer) {
return pc.setLocalDescription(offer);
}).then(function() {
// wait for ICE gathering to complete
return new Promise(function(resolve) {
console.log(pc.iceGatheringState);
if (pc.iceGatheringState === 'complete') {
resolve();
} else {
function checkState() {
console.log(pc.iceGatheringState);
if (pc.iceGatheringState === 'complete') {
pc.removeEventListener('icegatheringstatechange', checkState);
resolve();
}
}
pc.addEventListener('icegatheringstatechange', checkState);
}
});
}).then(function() {
var offer = pc.localDescription;
controller = new AbortController();
signal = controller.signal;
return timeoutPromise(30000, fetch('/offer', {
body: JSON.stringify({
sdp: offer.sdp,
type: offer.type,
"name":name,
"surname":surname
}),
headers: {
'Content-Type': 'application/json'
},
method: 'POST',
signal
}));
}).then(function(response) {
return response.json();
}).then(function(answer) {
if (answer.sdp == "" && answer.type == ""){
console.log("call rejected 167");
setTimeout(call_rejected, 1000);
return null;
}else{
return pc.setRemoteDescription(answer);
}
}).catch(function(e) {
setTimeout(call_rejected, 1000);
//alert(e);
console.log(e);
return null;
});
}
function negotiate_client(call_number) {
return clients_pc[clients_pc.length-1].createOffer({"offerToReceiveAudio":true,"offerToReceiveVideo":true}).then(function(offer) {
return clients_pc[clients_pc.length-1].setLocalDescription(offer);
}).then(function() {
// wait for ICE gathering to complete
return new Promise(function(resolve) {
console.log(clients_pc[clients_pc.length-1].iceGatheringState);
if (clients_pc[clients_pc.length-1].iceGatheringState === 'complete') {
resolve();
} else {
function checkStateClient() {
console.log(clients_pc[clients_pc.length-1].iceGatheringState);
if (clients_pc[clients_pc.length-1].iceGatheringState === 'complete') {
clients_pc[clients_pc.length-1].removeEventListener('icegatheringstatechange', checkStateClient);
resolve();
}
}
clients_pc[clients_pc.length-1].addEventListener('icegatheringstatechange', checkStateClient);
}
});
}).then(function() {
var offer = clients_pc[clients_pc.length-1].localDescription;
return fetch('/offer-client', {
body: JSON.stringify({
sdp: offer.sdp,
type: offer.type,
"desired_call":call_number,
"call_number":local_call_number
}),
headers: {
'Content-Type': 'application/json'
},
method: 'POST'
});
}).then(function(response) {
return response.json();
}).then(function(answer) {
return clients_pc[clients_pc.length-1].setRemoteDescription(answer);
}).catch(function(e) {
//alert(e);
console.log(e);
});
}
function call_rejected(){
console.log("call rejected");
console.log("251");
stop_peer_connection(false);
}
function stop_peer_connection(dc_message=true) {
console.log("stop peer connection");
//alert("stop peer connection");
$("#signal-audio").trigger("pause");
$("#signal-audio").currentTime = 0; // Reset time
// send disconnect message because iceconnectionstate slow to go in failed or in closed state
try{
if (dc.readyState == "open"){
if (dc_message){
dc.send("disconnected");
console.log("sending disconnect message");
}
}
}catch (e){
console.log(e);
}
try{
if (local_stream["audio"] != null){
local_stream.audio.stop();
local_stream.video.stop();
local_stream = {"audio":null,"video":null};
}
}
catch (e){
console.log(e);
}
$("#control_call_button").removeClass("d-none")
$("#stop_call_button").addClass("d-none")
document.getElementById('client-video-1').srcObject = null;
document.getElementById('server-video').srcObject = null;
document.getElementById('server-audio').srcObject = null;
document.getElementById('client-audio-2').srcObject = null;
document.getElementById('client-video-2').srcObject = null;
document.getElementById('client-audio-3').srcObject = null;
document.getElementById('client-video-3').srcObject = null;
try{
if (controller != null){
controller.abort();
}
if (dc.readyState != "open"){
pc.close();
}
}catch (e){
console.log(e);
}
}
function stop_client_peer_connection(call_number) {
if (local_call_number == 1){
if (call_number == 2){
document.getElementById('client-audio-2').srcObject = null;
document.getElementById('client-video-2').srcObject = null;
}else if (call_number == 3){
document.getElementById('client-audio-3').srcObject = null;
document.getElementById('client-video-3').srcObject = null;
}
}else if (local_call_number == 2){
if (call_number == 1){
document.getElementById('client-audio-2').srcObject = null;
document.getElementById('client-video-2').srcObject = null;
}else if (call_number == 3){
document.getElementById('client-audio-3').srcObject = null;
document.getElementById('client-video-3').srcObject = null;
}
}else{
if (call_number == 1){
document.getElementById('client-audio-2').srcObject = null;
document.getElementById('client-video-2').srcObject = null;
}else if (call_number == 2){
document.getElementById('client-audio-3').srcObject = null;
document.getElementById('client-video-3').srcObject = null;
}
}
}
function start_client(client_call_number,client_name,client_surname){
if (local_call_number == 1){
if (client_call_number == 2){
$("#listener-2").html("Άλλος ακροατής: "+client_name+" "+client_surname+":");
}else if (client_call_number == 3){
$("#listener-3").html("Άλλος ακροατής: "+client_name+" "+client_surname+":");
}
}else if (local_call_number == 2){
if (client_call_number == 1){
$("#listener-2").html("Άλλος ακροατής: "+client_name+" "+client_surname+":");
}else if (client_call_number == 3){
$("#listener-3").html("Άλλος ακροατής: "+client_name+" "+client_surname+":");
}
}else{
if (client_call_number == 1){
$("#listener-2").html("Άλλος ακροατής: "+client_name+" "+client_surname+":");
}else if (client_call_number == 2){
$("#listener-3").html("Άλλος ακροατής: "+client_name+" "+client_surname+":");
}
}
createLocalPeerConnection(client_call_number,client_name,client_surname);
clients_pc[clients_pc.length-1].onclose = function() {
// close data channel
// close local audio / video
clients_pc[clients_pc.length-1].getSenders().forEach(function(sender) {
sender.track.stop();
});
// close transceivers
if (clients_pc[clients_pc.length-1].getTransceivers) {
clients_pc[clients_pc.length-1].getTransceivers().forEach(function(transceiver) {
if (transceiver.stop) {
transceiver.stop();
}
});
}
clients_pc.splice(clients_pc.length-1, 1);
console.log("Local peer connection closed");
if (local_call_number == 1){
if (client_call_number ==2){
stream_client_2 = stream_client_3;
stream_client_3 = {"audio":null,"video":null};
$("#listener-2").html($("#listener-3").html());
$("#listener-3").html("Άλλος ακροατής:");
document.getElementById('client-audio-2').srcObject = stream_client_2.audio;
document.getElementById('client-audio-3').srcObject = null;
document.getElementById('client-video-2').srcObject = stream_client_2.video;
document.getElementById('client-video-3').srcObject = null;
}else{//client_call_number = 3
$("#listener-3").html("Άλλος ακροατής:");
document.getElementById('client-audio-3').srcObject = null;
document.getElementById('client-video-3').srcObject = null;
}
}else{
if (local_call_number == 2){
if (client_call_number ==1){
stream_client_2 = stream_client_3;
stream_client_3 = {"audio":null,"video":null};
$("#listener-2").html($("#listener-3").html());
$("#listener-3").html("Άλλος ακροατής:");
document.getElementById('client-audio-2').srcObject = stream_client_2.audio;
document.getElementById('client-audio-3').srcObject = null;
document.getElementById('client-video-3').srcObject = stream_client_2.video;
document.getElementById('client-video-3').srcObject = null;
}else{//client_call_number = 3
stream_client_3 = {"audio":null,"video":null};
$("#listener-3").html("Άλλος ακροατής:");
document.getElementById('client-audio-3').srcObject = null;
document.getElementById('client-video-3').srcObject = null;
}
}else{//local_call_number = 3
if (client_call_number ==1){
stream_client_2 = stream_client_3;
stream_client_3 = {"audio":null,"video":null};
$("#listener-2").html($("#listener-3").html());
$("#listener-3").html("Άλλος ακροατής:");
document.getElementById('client-audio-2').srcObject = stream_client_2.audio;
document.getElementById('client-audio-3').srcObject = null;
document.getElementById('client-video-2').srcObject = stream_client_2.video;
document.getElementById('client-video-3').srcObject = null;
}else{//client_call_number = 2
stream_client_3 = {"audio":null,"video":null};
$("#listener-3").html("Άλλος ακροατής:");
document.getElementById('client-audio-3').srcObject = null;
document.getElementById('client-video-3').srcObject = null;
}
}
}
};
negotiate_client(client_call_number);
constraints = {audio:true,video:true};
/*navigator.mediaDevices.getUserMedia(constraints).then(function(stream) {
stream.getTracks().forEach(function(track) {
clients_pc[clients_pc.length-1].addTrack(track, stream);
});
return negotiate_client(client_call_number);
}, function(err) {
alert('Could not acquire media: ' + err);
});
*/
}
function start(name,surname) {
$("#control_call_button").addClass("d-none");
$("#stop_call_button").removeClass("d-none");
$("#signal-audio").trigger("play");
pc = createPeerConnection();
dc = pc.createDataChannel('chat', {"ordered": true});
dc.onclose = function() {
};
dc.onopen = function() {
};
dc.onmessage = function(evt) {
console.log(evt.data);
data = JSON.parse(evt.data);
if(data["type"] == "closing-call-1"){
if (local_call_number == 1){
if (closing == false){
closing = true;
console.log("470");
stop_peer_connection();
}
}else{
stop_client_peer_connection(1);
}
}else if (data["type"] == "closing-call-2"){
if (local_call_number == 2){
if (closing == false){
closing = true;
console.log("480");
stop_peer_connection();
}
}else{
stop_client_peer_connection(2);
}
}else if (data["type"] == "closing-call-3"){
if (local_call_number == 3){
if (closing == false){
closing = true;
console.log("489");
stop_peer_connection();
}
}else{
stop_client_peer_connection(3);
}
}
if (data["type"] == "local_call_number"){
local_call_number = data["call_number"];
stream_client_1 = local_stream;
}
if (data["type"] == "new-client"){
var client_call_number = data["call_number"]
var client_name = data["name"]
var client_surname = data["surname"]
start_client(client_call_number,client_name,client_surname)
}
};
pc.onconnectionstatechange = (event) => {
let newCS = pc.connectionState;
if (newCS == "disconnected" || newCS == "failed" || newCS == "closed") {
console.log(newCS);
console.log("517");
stop_peer_connection();
}
}
pc.onclose = function() {
closing = true;
console.log("525");
stop_peer_connection(false);
// close data channel
if (dc) {
dc.close();
}
// close local audio / video
pc.getSenders().forEach(function(sender) {
sender.track.stop();
});
// close transceivers
if (pc.getTransceivers) {
pc.getTransceivers().forEach(function(transceiver) {
if (transceiver.stop) {
transceiver.stop();
}
});
}
pc = null;
console.log("Local peer connection closed");
//alert("Local peer connection closed");
};
//negotiate();
constraints = {audio:true,video:true};
navigator.mediaDevices.getUserMedia(constraints).then(function(stream) {
//local_stream = stream;
stream.getTracks().forEach(function(track) {
try {
pc.addTrack(track, stream);
if (track.kind == "video"){
//correct
local_stream.video = track;
document.getElementById('client-video-1').srcObject = stream;
}else{
local_stream.audio = track;
}
stream_client_1 = local_stream;
} catch(e){
//console.log(e);
}
});
return negotiate();
}, function(err) {
alert('Could not acquire media: ' + err);
});
}
$(document).ready(function(){
$("#control_call_button").on( "click", function() {
name = $("#name").val();
surname = $("#surname").val();
closing = false;
controller = null;
start(name,surname)
});
$("#stop_call_button").on( "click", function() {
closing = true;
console.log("595");
stop_peer_connection();
});
//debug code
/*$("#name").on( "focus",async function(){
for(var i=0;i<10;i++){
$("#control_call_button").click();
await sleep(2000);
$("#stop_call_button").click();
await sleep(2000);
}
});
*/
})
function sleep(ms) {
return new Promise(resolve => setTimeout(resolve, ms));
}
/*
window.addEventListener("beforeunload", function (e) {
console.log("Before unload");
fetch('/cancel_call', {
body: JSON.stringify({}),
headers: {
'Content-Type': 'application/json'
},
method: 'POST'
});
const sleep = ms => new Promise(r => setTimeout(r, 5000));
});
*/
after a few seconds of inactivity this code run:
pc.onconnectionstatechange = (event) => {
let newCS = pc.connectionState;
if (newCS == "disconnected" || newCS == "failed" || newCS == "closed") {
console.log(newCS);//failed
console.log("517");
stop_peer_connection();
}
}
I want to ask why this is happened and how can i keep the connection alive.
