When using Meteor, with the new authentication system, how can I get facebook access token, when logged with accounts-facebook package?
get it either from a Meteor.method:
// server
Meteor.methods({
getAccessToken : function() {
try {
return Meteor.user().services.facebook.accessToken;
} catch(e) {
return null;
}
}
});
// client
Meteor.call("getAccessToken", function(error, accessToken){
console.log(accessToken);
})
or publish it:
//server
Meteor.publish("currentUserAccessToken", function(){
var self = this;
if (this.userId()){
handle = Meteor.users.find(this.userId()).observe({
added: function(user){
self.set("currentUserAccessToken", user._id, {value: user.services.facebook.accessToken});
self.flush();
},
changed: function(user){
self.set("currentUserAccessToken", user._id, {value: user.services.facebook.accessToken});
self.flush();
}
});
this.onStop(function() {
handle.stop();
});
}
});
//client
var AccessToken = new Meteor.Collection("currentUserAccessToken");
Meteor.subscribe("currentUserAccessToken");
//access the value
var accessToken = AccessToken.findOne().value;
Updating and simplifying Lloyd's answer, we get this:
server
Meteor.publish("currentAccessToken", function(){
return Meteor.users.find(this.userId, {fields: {'services.facebook.accessToken': 1}});
});
client
Meteor.autosubscribe(function(){
var newUser = Meteor.user();
Meteor.subscribe('currentAccessToken');
});
It updates every time your user changes status, and access token can be accessed (when exists) by Meteor.user().services.facebook.accessToken
Related
Below I try to respond with a stream when I receive ticker updates.
+page.server.js:
import YahooFinanceTicker from "yahoo-finance-ticker";
const ticker = new YahooFinanceTicker();
const tickerListener = await ticker.subscribe(["BTC-USD"])
const stream = new ReadableStream({
start(controller) {
tickerListener.on("ticker", (ticker) => {
console.log(ticker.price);
controller.enqueue(ticker.price);
});
}
});
export async function load() {
return response????
};
Note: The YahooFinanceTicker can't run in the browser.
How to handle / set the response in the Sveltekit load function.
To my knowledge, the load functions cannot be used for this as their responses are JS/JSON serialized. You can use an endpoint in +server to return a Response object which can be constructed from a ReadableStream.
Solution: H.B. comment showed me the right direction to push unsollicited price ticker updates the client.
api route: yahoo-finance-ticker +server.js
import YahooFinanceTicker from "yahoo-finance-ticker";
const ticker = new YahooFinanceTicker();
const tickerListener = await ticker.subscribe(["BTC-USD"])
/** #type {import('./$types').RequestHandler} */
export function GET({ request }) {
const ac = new AbortController();
console.log("GET api: yahoo-finance-ticker")
const stream = new ReadableStream({
start(controller) {
tickerListener.on("ticker", (ticker) => {
console.log(ticker.price);
controller.enqueue(String(ticker.price));
}, { signal: ac.signal });
},
cancel() {
console.log("cancel and abort");
ac.abort();
},
})
return new Response(stream, {
headers: {
'content-type': 'text/event-stream',
}
});
}
page route: +page.svelte
<script>
let result = "";
async function getStream() {
const response = await fetch("/api/yahoo-finance-ticker");
const reader = response.body.pipeThrough(new TextDecoderStream()).getReader();
while (true) {
const { value, done } = await reader.read();
console.log("resp", done, value);
if (done) break;
result += `${value}<br>`;
}
}
getStream();
</script>
<section>
<p>{#html result}</p>
</section>
I'm trying to have a service worker intercept fetch requests coming from a client-side SvelteKit load function. The network requests are being made, but the fetch event is not being triggered.
The fetch request from the load function is going to /api/allTeams, which is cached as reported by chrome devtools, but like I said, it's not getting intercepted. All the function does it fetch the data, and return it in a prop.
Also, every couple minutes I run invalidateAll(), to reload the data, and even those requests aren't being picked up by the SW.
Thanks!
--reese
src/service-worker.js:
import { build, version } from '$service-worker';
self.addEventListener('fetch', function (event) {
console.log("fetch")
event.respondWith(
fetch(event.request).catch(function () {
return caches.match(event.request);
}),
);
});
self.addEventListener('install', async function (event) {
event.waitUntil(
caches.open("ccs-" + version).then(function (cache) {
cache.add("/api/allTeams")
cache.addAll(build)
return;
}),
);
});
src/app.html:
<script>
const registerServiceWorker = async () => {
if ("serviceWorker" in navigator) {
try {
const registration = await navigator.serviceWorker.register("/service-worker.js", {
scope: "*",
});
if (registration.installing) {
console.log("Service worker installing");
} else if (registration.waiting) {
console.log("Service worker installed");
} else if (registration.active) {
console.log("Service worker active");
}
} catch (error) {
console.error(`Registration failed with ${error}`);
}
}
};
registerServiceWorker()
</script>
src/+page.ts:
export async function load(request: Request) {
const searchQuery = new URL(request.url).searchParams.get("q")
const apiUrl = new URL(request.url)
apiUrl.pathname = "/api/allTeams"
const req = await fetch(apiUrl)
const data = await req.json()
return {data, searchQuery};
}
After login functionality, I am saving my auth token in browser's localStorage, so that i can authenticate each action fired to the server. After login i have to refresh my browser to retrieve my token, since root component is not rerendered. is there any way to rerender index.js? I am building an electron app, so browser refresh is not an option.
in index.js
const AUTH_TOKEN = localStorage.getItem('user')
if(AUTH_TOKEN){
axios.defaults.headers.common['Authorization'] = AUTH_TOKEN;
store.dispatch({type: AUTHENTICATED});
}
but this will only get rendered only the first time app loads. Store and routes are defined inside. So after login auth token will be saved in localstorage but its not updated in app. Any ideas?
You can just set the axios authorization header after saving the auth token.
So this is what i did
In Auth action
localStorage.setItem('user', response.data.auth_token);
localStorage.setItem('name', response.data.user.name);
localStorage.setItem('email', response.data.user.email);
axios.defaults.headers.common['Authorization'] = response.data.auth_token;
dispatch({ type: AUTHENTICATED });
you can manage token like there, its updated on token expire, token change
const watchToken = (delay) => {
return setTimeout(() => {
myApi.getToken().then(res => {
if (res.token) {
store.dispatch({ type: AUTHENTICATED })
} else {
store.dispatch({ type: NOT_AUTHENTICATED })
}
})
}, delay);
}
class App extends Component {
tokenManager;
constructor() {
super();
this.state = {
isReady: false
};
}
componentWillMount() {
this.tokenManager = watchToken(20000)
}
componentWillUpdate(nextProps, nextState) {
if (nextProps.TOKEN !== this.props.TOKEN) {
this.tokenManager = watchToken(20000);
}
}
componentWillUnmount() {
this.tokenManager.clearTimeout();
}
render() {
return (
<div>
</div>
);
}
}
I'mm working on a service worker, who should just cache some specific files.
But after implementation and refresh (yes I enabled "dumb sw after reload") there are much more files "loaded via the sw" then I added in the "files to cache" list.
I'm new with the service worker and have no idea what is wrong. I just followed some tutorials about it.
Here the code. Perhaps I am on the complete wrong way.
if ('serviceWorker' in navigator) {
window.addEventListener('load', function() {
navigator.serviceWorker.register('/worker.js').then(function(registration) {
}, function(err) {
console.log('ServiceWorker registration failed: ', err);
});
});
}
var debugMode = false;
//Variables to cache
var CACHE_NAME = 'companyname-cache-1511794947915';
var urlsToCache = [
'/typo3conf/ext/companyname/Resources/Public/css/animate.css',
'/typo3conf/ext/companyname/Resources/Public/css/bootstrap.css',
'/typo3conf/ext/companyname/Resources/Public/css/bootstrap.min.css',
'/typo3conf/ext/companyname/Resources/Public/css/bootstrap-theme.css',
'/typo3conf/ext/companyname/Resources/Public/css/bootstrap-theme.min.css',
'/typo3conf/ext/companyname/Resources/Public/css/main.css',
'/typo3conf/ext/companyname/Resources/Public/css/et/override.css',
'/typo3conf/ext/companyname/Resources/Public/css/et/screen-full.css',
'/typo3conf/ext/companyname/Resources/Public/css/et/screen-full.min.css',
'/typo3conf/ext/companyname/Resources/Public/Icons/favicon.ico',
'/typo3conf/ext/companyname/Resources/Public/Icons/FaviconTouch/android-chrome-512x512.png',
];
self.addEventListener('install', function(event) {
// Perform install steps
event.waitUntil(
caches.open(CACHE_NAME)
.then(function(cache) {
return cache.addAll(urlsToCache);
})
);
});
self.addEventListener("activate", function(event) {
event.waitUntil(
caches.keys().then(function(cacheNames) {
return Promise.all(
cacheNames.map(function(cacheName) {
if(debugMode) {
console.log('actual cache name: %o', CACHE_NAME);
console.log('name inside the cache: %o', cacheName);
}
if ((cacheName.indexOf('companyname-cache-') !== -1) && (cacheName !== CACHE_NAME)) {
if(debugMode) {
console.log("old cache deleted");
}
return caches.delete(cacheName);
}
})
);
})
);
});
self.addEventListener('fetch', function(event) {
event.respondWith(
caches.match(event.request)
.then(function(response) {
if (response) {
if(debugMode) {
console.log("fetch 1");
}
return response;
}
var fetchRequest = event.request.clone();
return fetch(fetchRequest).then(
function(response) {
if(!response || response.status !== 200 || response.type !== 'basic') {
if(debugMode) {
console.log("fetch 2");
}
return response;
}
var responseToCache = response.clone();
caches.open(CACHE_NAME)
.then(function(cache) {
cache.put(event.request, responseToCache);
});
if(debugMode) {
console.log("fetch 3");
}
return response;
}
);
})
);
});
The code in your SW works like this:
On installation, add all items in the URL LIST to the cache
On activation, check that the cache has items only for the CACHE NAME
On a fetch event: 1st check if the requested resource is in the cache and return if if found; 2nd if the requested resource was NOT in the cache, request it from the network AND put it in the cache
The last part of #3 causes the problem in your SW code – it is adding everything requested to the cache so in the future they're available from the cache.
You can see the problem in your code if you look for the last occurrence of this:
caches.open(CACHE_NAME)
That's the part of your code when something WASN'T found from the cache AND was requested from the network. The code is then putting it into the cache – that's not what you wanted.
I am using SocketIO and redis based on the following code,
var sub = redis.createClient();
var pub = redis.createClient();
sub.subscribe('chat');
io.use(socketHandshake({store: sessionStore, key:'jsessionid', secret:'secret', parser:cookieParser()}));
io.on('connection', function (socket) {
socket.on('chat', function (message) {
// io.emit('chat', "hello world");
pub.publish('chat', "hello world");
});
sub.on('message', function (channel, message) {
io.emit(channel, message);
});
});
This is the base code. I have modified the code so that if any user goes offline, in server side I am storing the messages in RSMQ(Redis Simple Message Queue) and when user comes online, the message is fetched from queue and emits to the user.I have used the following code to achieve this.I have stored the user status in an array.
var fs = require('fs')
, http = require('http')
, socketio = require('socket.io');
var redis = require('redis');
var store = redis.createClient();
var pub = redis.createClient();
var sub = redis.createClient();
RedisSMQ = require("rsmq");
rsmq = new RedisSMQ( {host: "127.0.0.1", port: 6379, ns: "rsmq"} );
var active_users=[];
var inactive_users=[];
var user_status=[];
var channel_users=[];
var users_queue=[];
var socket_ids=[];
var cname,qn;
var clients=[];
var server = http.createServer(function(req, res) {
res.writeHead(200, { 'Content-type': 'text/html'});
res.end(fs.readFileSync(__dirname + '/index.html'));
}).listen(9000, function() {
console.log('Listening at: http://localhost:9000');
});
socketio.listen(server).on('connection', function (socket) {
socket.on('login', function(data){
console.log('a user ' + data.userId + ' connected'+socket.id);
//saving userId to array with socket ID
active_users[socket.id] = data.userId;
socket_ids[data.userId]=socket.id;
clients[socket.id] = socket;
user_status[data.userId]="online";
});
socket.on('message', function (msg) {
console.log('Message Received: ', msg);
socket.broadcast.emit('message', msg);
});
socket.on('json', function (msg) {
if(msg.channel_name=='UserState'){
rsmq.listQueues(function(err,resp){
//console.log("QUEUES LIST"+resp);
});
if(msg.user_state=='active'){
store.hmset("active_users."+msg.sender_id,{"user":"online"});
user_status[msg.sender_id]="online";console.log(user_status);
if(users_queue[msg.sender_id]!=undefined && users_queue[msg.sender_id].length>0){
console.log("USERS QUEUE:"+users_queue[msg.sender_id]['0']);
for(var i=0;i<users_queue[msg.sender_id].length;i++){
cname=users_queue[msg.sender_id][i].split('_')[0];//get channel name from queue name
qn=users_queue[msg.sender_id][i];
rsmq.getQueueAttributes({qname:users_queue[msg.sender_id][i]},function(err,resp){
console.log("RESP:"+resp.msgs);
if(resp.msgs>0){ //if there are messages in queue......
for(var j=0;j<resp.msgs;j++){
rsmq.popMessage({qname:qn},function(err,resp){
console.log(resp);
var sid=socket_ids[msg.sender_id]; console.log("SOCKETID:"+sid); //get socket.id for the user
pub.publish(cname,resp.message);
});
}
}
});
}
}
}
else{
store.hmset("active_users."+msg.sender_id,{"status":"offline"});
user_status[msg.sender_id]="offline";
}
}
if(msg.channel_name=='ShareConversation'){
var channel=msg.conversations_data.conversation_id;//have to change to conversation_id or whatever channel.....
sub.subscribe(channel);
channel_users[channel]=[];
var m=msg.conversations_data.users.split(',');
for(var i=0;i<m.length;i++){
channel_users[channel].push(m[i]);
}
for(var i=0;i<channel_users[channel].length;i++){
var q=channel_users[channel][i].split('#')[0].replace(/(^\s+|\s+$)/g, '');
var queue_name=channel+"_"+q;console.log(queue_name);
var uname=channel_users[channel][i].replace(/(^\s+|\s+$)/g, '');
users_queue[uname]=[];
users_queue[uname].push(queue_name);
rsmq.createQueue({qname:queue_name}, function (err, resp) {
console.log(err);
console.log(queue_name);
if (resp===1) {
console.log("queue created");
}
});
}
}
socket.broadcast.emit('json', msg);
});
sub.on('message', function (channel, message) {
console.log("Message: " + message);
for(var i=0;i<channel_users[channel].length;i++){
var c=channel_users[channel][i].replace(/(^\s+|\s+$)/g, '');console.log("channel_users:"+channel_users[channel][i]);console.log("USER STATE :"+ user_status[c]);
if(user_status[c]=='offline'){
//send notification.........
//put messages in queue.......
var q=channel_users[channel][i].split('#')[0].replace(/(^\s+|\s+$)/g, '');
var queue_name=channel+"_"+q;console.log(queue_name);
rsmq.sendMessage({qname:queue_name, message:message}, function (err, resp) {
console.log(err);
if (resp) {
console.log("Message sent. ID:", resp);
}
});
}
}
socket.emit(channel, message);
});
});
This is my entire code. Here the issue is when the user goes offline, the message gets saved in queue multiple times and when the user comes online, the messages are received multiple times as there are duplicate messages saved in queue. How to overcome this.Please help....