Dev thanks for opening this question and I hope so you can help me to get rid out if the situation.
I am new to the Google cloud service and I am learning the cloud task, I have to create the queue programmatically and add some arguments like processing rate, bucket size. i am not able to find any solution till now.
i am creating the queue in the following way
const createQueue = async (
queueName: string
) => {
const project = 'projectname'; // Your GCP Project id
const queue = queueName; // Name of the Queue to create
const location = 'location name' // The GCP region in which to create the queue
const {
v2beta3
} = require('#google-cloud/tasks');
const client = new v2beta3.CloudTasksClient();
try {
const [response] = await client.createQueue({
parent: client.locationPath(project, location),
queue: {
name: client.queuePath(project, location, queue),
appEngineHttpQueue: {
appEngineRoutingOverride: {
service: 'default'
}
},
},
});
console.log(`Created queue ${response.name}`);
return response.name;
} catch (error) {
console.error(Error(error.message));
}
// return null
}
how can I add the arguments like processing rate, bucket size, and the max concurrent rate
you need to add this property "rateLimits" to your "queue" property for example
queue: {
name:client.queuePath(project,location,queue),
appEngineHttpQueue:{
appEngineRoutingOverride:{
service:default
},
rateLimits:{
maxDispatchesPerSecond:500
},
retryConfig:{
maxAttempts:1
}
}
keep in mind that the property "max_burst_size" is equal to "bucket_size"
Related
I was wondering how to make my app save data after restart? (The user can delete task and add new task to list, as well as check the box that the task is done. I want the app to save this data so when the user exists the app it will display all the tasks that he left the app with)
I was reading on google for few hours now, I got to
[1]: https://flutter.dev/docs/cookbook/persistence/reading-writing-files
This link as someone recommended on a similar post. But after reading it through I am a bit confused about where to start with my app.
Including some of my code and if you could help me I would really appreciate it as after hours of reading and watching tutorials I am still quite unsure where to start or which way of doing this is best.
My main.dart is this
void main() {
runApp(MyApp());
}
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return ChangeNotifierProvider(
create: (context) =>
TaskData(), //changing builder: to create: fixed the errors i been having
child: MaterialApp(
home: TasksScreen(),
),
);
}
}
class TaskData extends ChangeNotifier {
List<Task> _tasks = [
Task(name: "Sample task 1"),
Task(name: "Sample task 2"),
Task(name: "Sample task 3"),
];
UnmodifiableListView<Task> get tasks {
return UnmodifiableListView(_tasks);
}
int get taskCount {
return _tasks.length;
}
void addTask(String newTaskTitle) {
final task = Task(name: newTaskTitle);
_tasks.add(task);
notifyListeners();
}
void updateTask(Task task) {
task.toggleDone();
notifyListeners();
}
void deleteTask(Task task) {
_tasks.remove(task);
notifyListeners();
}
Thank you so much!
The basic method is using the device local storage.
1 - Add the shared_preferences in your pubspec.yaml
2 - Create a class to write and read data :
import 'dart:convert';
import 'package:shared_preferences/shared_preferences.dart';
class StoreData {
StoreData._privateConstructor();
static final StoreData instance = StoreData._privateConstructor();
Future<void> saveString(String key, String value) async {
try{
SharedPreferences pref = await SharedPreferences.getInstance();
final encodedValue = base64.encode(utf8.encode(value));
pref.setString(key, encodedValue);
} catch (e){
print('saveString ${e.toString()}');
}
}
Future<String> getString(String key) async {
SharedPreferences pref = await SharedPreferences.getInstance();
final value = pref.getString(key) == null ? '' : pref.getString(key);
if (value.length > 0) {
final decodedValue = utf8.decode(base64.decode(value));
return decodedValue.toString();
}
return '';
}
Future<bool> remove(String key) async {
SharedPreferences pref = await SharedPreferences.getInstance();
return pref.remove(key);
}
}
3 Use :
Save Data:
StoreData.instance.saveString('name', 'sergio');
Retrieve Data:
final String storedName = await StoreData.instance.getString('name');
print('The name is $storedName');
We have many other methods, like use a SQlite, NoSql or a Database in back-end, but the local storage is the most basic case
What you need is a database or a document based data storage. You can store data in a local sqlite db, using sqflite plugin. Or you can store in a JSON asset file.
You can also use a server or cloud service. Firebase is pretty well integrated with flutter, but AWS and Azure are also great.
You can write the data in a text file in the asset, but that would very complicated.
I am developing an Electron application with the integration of React.js as a front-end framework, which will be more like a calling application.
In that application-specific users can have multiple calls incoming, outgoing, mute | unmute calls, hold | unhold calls, etc.
For this functionality to be achieved we have our own sip server, and for integrating that SIP server, on the frontend we are using a library which is known as SIP.JS.
SIP.JS provides us mostly all the predefined functions to make a call, receive a call, mute, unmute, blind transfer, attended transfer, etc.
But when it comes to having a call conference, it doesn't have proper documentation for that.
SIP.JS specifies to us that we can use FreeSWITCH as well as ASTERISK in order to achieve the functionality, but with our specific requirements, no additional server needs to be integrated.
We have also referred to rfc documentation for the call conference, but no such progress was there.
So far what we did is:
Registered the userAgent
Code for Incoming call integrated
Code for outgoing calls integrated
multiple session handling is achieved, for multiple calls
mute | unmute, hold | unhold.
DTMF functionality
Blind Transfer, Attended Transfer
Ring all Devices
In this scenario of call conference, I guess we have to make changes in Incoming and outgoing session handling functions.
For registration and incoming call in context:
const getUAConfig = async (_extension, _name) => {
let alreadyLogin = '';
try {
alreadyLogin = 'yes';
if (alreadyLogin == 'yes') {
_displayname = _name;
_sipUsername = _extension;
_sipServer = 'SIP SERVER';
_sipPassword = 'SIP PASSWORD';
_wssServer = 'WSS SERVER;
const uri = UserAgent.makeURI('sip:' + _sipUsername + '#' + _sipServer);
const transportOptions = {
wsServers: 'WSS SERVER',
traceSip: true,
maxReconnectionAttempts: 1,
};
const userAgentOptions = {
uri: uri,
transportOptions: transportOptions,
userAgentString: 'App name',
authorizationPassword: _sipPassword,
sipExtension100rel: 'Supported',
sipExtensionReplaces: 'Supported',
register: true,
contactTransport: 'wss',
dtmfType: 'info',
displayName: _name,
sessionDescriptionHandlerFactoryOptions: {
peerConnectionOptions: {
rtcpMuxPolicy: 'negotiate',
iceCheckingTimeout: 1000,
iceTransportPolicy: 'all',
iceServers: [{ urls: 'stun:stun.l.google.com:19302' }],
},
},
};
userAgent = await new UserAgent(userAgentOptions);
const registerOptions = {
extraContactHeaderParams: [],
};
registerer = await new Registerer(userAgent, registerOptions);
registerer.stateChange.addListener((newState) => {
});
userAgent.start().then(async () => {
console.log('Connected with WebSocket.');
// Send REGISTER
await registerer
.register()
.then((request) => {
console.log('Successfully sent REGISTER, object is here');
dispatch({
type: USER_REGISTERED,
payload: true,
});
})
.catch((error) => {
console.log('Failed to send REGISTER');
});
});
return { userAgent, registerer };
} else {
return null;
}
} catch (error) {
console.log(error.message + '');
return null;
}
};
Outgoing functionality:
const dilaerFun = (inputNumber, userAgentInfo) => {
var session;
var uri = UserAgent.makeURI(
`URI which we wanna call (sip number)`
);
session = new Inviter(userAgentInfo, uri);
session
.invite()
.then((request) => {
console.log('Successfully sent INVITE');
sessionInfoAdd(session);
session.stateChange.addListener(async (state) => {
switch (state) {
case 'Established':
setMissedStatus(null);
console.log('established outgoing....');
//outgoing call log-----
const mediaElement = document.getElementById(
`mediaElement${session._id}`
);
const remoteStream = new MediaStream();
session.sessionDescriptionHandler.peerConnection
.getReceivers()
.forEach((receiver) => {
if (receiver.track) {
remoteStream.addTrack(receiver.track);
}
});
mediaElement.srcObject = remoteStream;
mediaElement.play();
break;
case 'Terminated':
console.log('terminated');
dispatch({
type: DEMO_STATE,
payload: session._id,
});
break;
default:
break;
}
});
})
.catch((error) => {
console.error(' Failed to INVITE');
console.error(error.toString());
});
};
Array of sessions are maintained by:
const sessionInfoAdd = (session) => {
dispatch({
type: SESSION_STORE,
payload: session,
});
};
Variable in which all sessions are stored is:
sessionInfo:[]
NOTE: getUAConfig() is called as soon as the application is started.
dialerFun() is called when we want to dial a specific number.
sessionInfoAdd() is called in both getUAConfig and dialerFun, as they are codes for incoming and outgoing calls.
when sessionInfoAdd() is triggered, the particular session which we get in return is added in the sessionInfo (Array) for the maintenance of sessions.
SIP.JS is just a library so you will have to get the conference setup on the FreeSWITCH or Asterisk (FreeSWITCH is the better in my opinion)
Doing this is fairly straight forward, at your app level you need a way to get calls across to the box after checking the details like access ID and any auth you want to add, (like a PIN.)
Once you have that done, you can forward that to an extension specifically set for conferencing or have a dynamic conference setup by send from the app towards a specific gateway/dialplan to do this.
The FreeSWITCH software has a steep learning curve on it but this helped me when I was doing something similar: https://freeswitch.org/confluence/display/FREESWITCH/mod_conference
You can also code you own conf if you wish.
I am developing a website in NextJs and using MongoDB as a database. This code is what connects to the database and keeps it in cache.
import { MongoClient } from "mongodb";
let cache = {};
export default async function connect() {
if (cache?.client?.isConnected()) {
return cache;
}
const opts = {
useNewUrlParser: true,
useUnifiedTopology: true,
};
return MongoClient.connect(process.env.DATABASE_URL, opts).then((client) => {
cache = {
db: client.db("bd"),
client,
};
return {
client,
db: client.db("bd"),
};
});
}
I imagine that this code should cause only 1 connection to be created but it is creating many more connections. As in the photo below, 18 connections were created and dropped to 6 after I stopped use the site. Why are several connections being created? How do you make it just one?
This is an example of code that I am using on one of the routes to list users.
...
const { db, client } = await connect();
const { userThatMakeRequest } = req;
const { group } = req.query;
const users = await db
.collection("user")
.find(
{
roles: "team-user",
"team.id": userThatMakeRequest?.team?.id,
"group.id": group,
hasAccess: true,
},
{ projection: { password: 0 } }
)
.toArray();
res.status(200).json({
response: users || [],
});
The driver creates 1 or 2 connections to each known server for monitoring purposes. Application connections (the ones used for satisfying queries and writes) are separate.
If you create a client object and perform one query against a 3 node replica set running MongoDB 4.4, you'll end up with 7 total connections.
So I am trying to push an item to a list (joinedGrps) every time a user creates a group, but when I try to push any item to the list, the value set to an automatically generated id
But I want it to store like an array with indexing starts with 0 like the below example
CODE
const RDBuserRef = realDB.ref(`users/${userInfo.userId}/joinedGrps`);
const newRDBref = RDBuserRef.push(grpName).catch((err) => {
console.log(err);
});
So is it possible to do?
Alternatives methods are welcomed but it should be in Realtime Database
You need to use the set() method instead of the push() one, which "generates a unique key every time a new child is added to the specified Firebase reference".
In order to know which key to use, you need to first read the Array, add a new element and then, write it back.
The following will do the trick:
const groupRef = realDB.ref(`users/${userInfo.userId}/joinedGrps`);
groupRef
.get()
.then(snapshot => {
if (snapshot.exists()) {
const grpArray = snapshot.val();
grpArray.push('...');
groupRef.set(grpArray);
} else {
groupRef.set({ 0: 'Elem#1' });
}
})
.catch(function (error) {
console.error(error);
});
HOWEVER, if several users are able to update the database node you need to use a transaction. Since you need to read the array before writing it back, using a transaction is the only way to ensure that there are no conflicts with other users writing to the same location at the same time.
groupRef.transaction(currentArray => {
if (currentArray === null) {
return { 0: 'Elem#1' };
} else {
currentArray.push('....');
return currentArray;
}
}
I’m having issues figuring out how to connect the Relay Modern network layer with my websocket instance.
I’m currently instantiating a websocket instance as:
const subscriptionWebSocket = new ReconnectingWebSocket('ws://url.url/ws/subscriptions/', null, options);
I'm specifying the subscription and creating a new instance of requestSubscription:
const subscription = graphql`
subscription mainSubscription {
testData {
anotherNode {
data
}
}
}
`;
requestSubscription(
environment,
{
subscription,
variables: {},
onComplete: () => {...},
onError: (error) => {...},
onNext: (response) => {...},
updater: (updaterStoreConfig) => {...},
},
);
Which then allows me to send any subscription requests:
function subscriptionHandler(subscriptionConfig, variables, cacheConfig, observer) {
subscriptionWebSocket.send(JSON.stringify(subscriptionConfig.text));
return {
dispose: () => {
console.log('subscriptionHandler: Disposing subscription');
},
};
}
const network = Network.create(fetchQuery, subscriptionHandler);
through to my server (currently using Graphene-python), and I’m able to interpret the received message on the server.
However, what I’m having issues figuring out is how to respond to a subscription; for example, when something changes in my DB, I want to generate a response and return to any potential subscribers.
The question being, how do I connect the onMessage event from my websocket instance into my Relay Modern Network Layer? I've browsed through the source for relay but can't seem to figure out what callback, or what method should be implementing an onreceive.
Any tips are appreciated.
I've managed to make subscriptions with Relay Modern work as well and wanted to share my minimal setup, maybe it's helpful for someone!
Note that I'm not using WebSocket but the SubscriptionClient that can be found in subscriptions-transport-ws to manage the connection to the server.
Here's my minimal setup code:
Environment.js
import { SubscriptionClient } from 'subscriptions-transport-ws'
const {
Environment,
Network,
RecordSource,
Store,
} = require('relay-runtime')
const store = new Store(new RecordSource())
const fetchQuery = (operation, variables) => {
return fetch('https://api.graph.cool/relay/v1/__GRAPHCOOL_PROJECT_ID__', {
method: 'POST',
headers: {
'Accept': 'application/json',
'Content-Type': 'application/json'
},
body: JSON.stringify({
query: operation.text,
variables,
}),
}).then(response => {
return response.json()
})
}
const websocketURL = 'wss://subscriptions.graph.cool/v1/__GRAPHCOOL_PROJECT_ID__'
function setupSubscription(
config,
variables,
cacheConfig,
observer,
) {
const query = config.text
const subscriptionClient = new SubscriptionClient(websocketURL, {reconnect: true})
const id = subscriptionClient.subscribe({query, variables}, (error, result) => {
observer.onNext({data: result})
})
}
const network = Network.create(fetchQuery, setupSubscription)
const environment = new Environment({
network,
store,
})
export default environment
NewLinkSubscription.js
import {
graphql,
requestSubscription
} from 'react-relay'
import environment from '../Environment'
const newLinkSubscription = graphql`
subscription NewLinkSubscription {
Link {
mutation
node {
id
description
url
createdAt
postedBy {
id
name
}
}
}
}
`
export default (onNext, onError, onCompleted, updater) => {
const subscriptionConfig = {
subscription: newLinkSubscription,
variables: {},
onError,
onNext,
onCompleted,
updater
}
requestSubscription(
environment,
subscriptionConfig
)
}
Now you can simply use the exported function to subscribe. For example, in one of my React components in componentDidMount I can now do the following:
componentDidMount() {
NewLinkSubscription(
response => console.log(`Received data: `, response),
error => console.log(`An error occurred:`, error),
() => console.log(`Completed`)
)
}
Note that the SubscriptionClient can only be used if your server implements this protocol!
If you want to learn more, check out the fullstack How to GraphQL tutorial that describes in detail how to make subscriptions work with Relay Modern.
I’ll just write down how I’ve approached this issue after the assistance found in this thread. It might be usable for someone else. This is very dependent on the server-side solution that you've chosen.
My approach:
Firstly I built a SubscriptionHandler that will handle the requestStream#subscribeFunction through SubscriptionHandler#setupSubscription.
The SubscriptionHandler instantiates a WebSocket (using a custom version of ReconnectingWebSockets) and attaches the onmessage event to an internal method (SubscriptionHandler#receiveSubscriptionPayload) which will add the payload to the corresponding request.
We create new subscriptions through SubscriptionHandler#newSubscription which will use the internal attribute SubscriptionHandler.subscriptions to add a keyed entry of this subscription (we use an MD5-hash util over the query and variables); meaning the object will come out as:
SubscriptionHandler.subscriptions = {
[md5hash]: {
query: QueryObject,
variables: SubscriptionVariables,
observer: Observer (contains OnNext method)
}
Whenever the server sends a subscription response the SubscriptionHandler#receiveSubscriptionPayload method will be called and it will identify what subscription the payload belongs to by using the query/variables md5 hash, then use the SubscriptionHandler.subscriptions observer onNext method.
This approach requires the server to return a message such as:
export type ServerResponseMessageParsed = {
payload: QueryPayload,
request: {
query: string,
variables: Object,
}
}
I do not know if this is a great way of handling subscriptions, but it works for now with my current setup.
SubscriptionHandler.js
class SubscriptionHandler {
subscriptions: Object;
subscriptionEnvironment: RelayModernEnvironment;
websocket: Object;
/**
* The SubscriptionHandler constructor. Will setup a new websocket and bind
* it to internal method to handle receving messages from the ws server.
*
* #param {string} websocketUrl - The WebSocket URL to listen to.
* #param {Object} webSocketSettings - The options object.
* See ReconnectingWebSocket.
*/
constructor(websocketUrl: string, webSocketSettings: WebSocketSettings) {
// All subscription hashes and objects will be stored in the
// this.subscriptions attribute on the subscription handler.
this.subscriptions = {};
// Store the given environment internally to be reused when registering new
// subscriptions. This is required as per the requestRelaySubscription spec
// (method requestSubscription).
this.subscriptionEnvironment = null;
// Create a new WebSocket instance to be able to receive messages on the
// given URL. Always opt for default protocol for the RWS, second arg.
this.websocket = new ReconnectingWebSocket(
websocketUrl,
null, // Protocol.
webSocketSettings,
);
// Bind an internal method to handle incoming messages from the websocket.
this.websocket.onmessage = this.receiveSubscriptionPayload;
}
/**
* Method to attach the Relay Environment to the subscription handler.
* This is required as the Network needs to be instantiated with the
* SubscriptionHandler's methods, and the Environment needs the Network Layer.
*
* #param {Object} environment - The apps environment.
*/
attachEnvironment = (environment: RelayModernEnvironment) => {
this.subscriptionEnvironment = environment;
}
/**
* Generates a hash from a given query and variable pair. The method
* used is a recreatable MD5 hash, which is used as a 'key' for the given
* subscription. Using the MD5 hash we can identify what subscription is valid
* based on the query/variable given from the server.
*
* #param {string} query - A string representation of the subscription.
* #param {Object} variables - An object containing all variables used
* in the query.
* #return {string} The MD5 hash of the query and variables.
*/
getHash = (query: string, variables: HashVariables) => {
const queryString = query.replace(/\s+/gm, '');
const variablesString = JSON.stringify(variables);
const hash = md5(queryString + variablesString).toString();
return hash;
}
/**
* Method to be bound to the class websocket instance. The method will be
* called each time the WebSocket receives a message on the subscribed URL
* (see this.websocket options).
*
* #param {string} message - The message received from the websocket.
*/
receiveSubscriptionPayload = (message: ServerResponseMessage) => {
const response: ServerResponseMessageParsed = JSON.parse(message.data);
const { query, variables } = response.request;
const hash = this.getHash(query, variables);
// Fetch the subscription instance from the subscription handlers stored
// subscriptions.
const subscription = this.subscriptions[hash];
if (subscription) {
// Execute the onNext method with the received payload after validating
// that the received hash is currently stored. If a diff occurs, meaning
// no hash is stored for the received response, ignore the execution.
subscription.observer.onNext(response.payload);
} else {
console.warn(Received payload for unregistered hash: ${hash});
}
}
/**
* Method to generate new subscriptions that will be bound to the
* SubscriptionHandler's environment and will be stored internally in the
* instantiated handler object.
*
* #param {string} subscriptionQuery - The query to subscribe to. Needs to
* be a validated subscription type.
* #param {Object} variables - The variables for the passed query.
* #param {Object} configs - A subscription configuration. If
* override is required.
*/
newSubscription = (
subscriptionQuery: GraphQLTaggedNode,
variables: Variables,
configs: GraphQLSubscriptionConfig,
) => {
const config = configs || DEFAULT_CONFIG;
requestSubscription(
this.subscriptionEnvironment,
{
subscription: subscriptionQuery,
variables: {},
...config,
},
);
}
setupSubscription = (
config: ConcreteBatch,
variables: Variables,
cacheConfig: ?CacheConfig,
observer: Observer,
) => {
const query = config.text;
// Get the hash from the given subscriptionQuery and variables. Used to
// identify this specific subscription.
const hash = this.getHash(query, variables);
// Store the newly created subscription request internally to be re-used
// upon message receival or local data updates.
this.subscriptions[hash] = { query, variables };
const subscription = this.subscriptions[hash];
subscription.observer = observer;
// Temp fix to avoid WS Connection state.
setTimeout(() => {
this.websocket.send(JSON.stringify({ query, variables }));
}, 100);
}
}
const subscriptionHandler = new SubscriptionHandler(WS_URL, WS_OPTIONS);
export default subscriptionHandler;
For anyone stumbling across this recently, I did not have success with either the solutions above because of recent updates in the libraries involved. Yet they were a great source to start and I put up together a small example based on the official relay modern todo example, it is very minimalistic and uses helpers libraries from Apollo but works well with relay modern:
https://github.com/jeremy-colin/relay-examples-subscription
It includes both server and client
Hope it can help
I think this repo would fit your needs.
Helps you creating your subscriptions server-side