I created a client-server system including:
a node.js server (with module ws);
a WebClient;
a QtClient (using Qt5.4 and QWebSocket).
The QtClient sends and receives strings via the method QWebSocket.sendTextMessage (QString s). How can I send an array of strings?
OTHER INFO:
The WebClient sends an array using JSON:
# index.html (WebClient)
socket.onopen = function() {
var array = {
value1: "WebClient value1 = v1",
value2: "WebClient value2 = v2"
};
socket.send(JSON.stringify(array), {binary: true, mask: false});
};
# server.js
socket.on('connection', function(ws) {
ws.on('message', function(message) {
var array = JSON.parse(message);
console.log(array["value1"]);
console.log( array["value2"]);
});
});
# console node
C:\Users\PietroP\Desktop\cs\v0.3>node server.js
Server connect on http://192.168.1.60:3000/
a user connected
WebClient value1 : v1
WebClient value2 : v2
QWebSocket class does not have direct implementation for sending arrays. You can send binary or text messages. For details please refer to:
http://doc.qt.io/qt-5/qwebsocket.html
Here is an alternative approach:
You can convert your array into a long string using something like
str = array.toString() // This is psuedo code
in a loop and send from the sender side. Then on the receiver side you can get parse it using a method such as
str.split(...);
Hope that heps!
Edit: You've probably already noticed that: in your sample code what JSON.stringify(array) and JSON.parse(message) do is nothing but converting array to string and then parse the string into array again.
Related
I'm using OKHttpClient in a Kotlin app to post a file to an API that gets processed. While the process is running the API is sending back messages to keep the connection alive until the result has been completed. So I'm receiving the following (this is what is printed out to the console using println())
{"status":"IN_PROGRESS","transcript":null,"error":null}
{"status":"IN_PROGRESS","transcript":null,"error":null}
{"status":"IN_PROGRESS","transcript":null,"error":null}
{"status":"DONE","transcript":"Hello, world.","error":null}
Which I believe is being separated by a new line character, not a comma.
I figured out how to extract the data by doing the following but is there a more technically correct way to transform this? I got it working with this but it seems error-prone to me.
data class Status (status : String?, transcript : String?, error : String?)
val myClient = OkHttpClient ().newBuilder ().build ()
val myBody = MultipartBody.Builder ().build () // plus some stuff
val myRequest = Request.Builder ().url ("localhost:8090").method ("POST", myBody).build ()
val myResponse = myClient.newCall (myRequest).execute ()
val myString = myResponse.body?.string ()
val myJsonString = "[${myString!!.replace ("}", "},")}]".replace (",]", "]")
// Forces the response from "{key:value}{key:value}"
// into a readable json format "[{key:value},{key:value},{key:value}]"
// but hoping there is a more technically sound way of doing this
val myTranscriptions = gson.fromJson (myJsonString, Array<Status>::class.java)
An alternative to your solution would be to use a JsonReader in lenient mode. This allows parsing JSON which does not strictly comply with the specification, such as in your case multiple top level values. It also makes other aspects of parsing lenient, but maybe that is acceptable for your use case.
You could then use a single JsonReader wrapping the response stream, repeatedly call Gson.fromJson and collect the deserialized objects in a list yourself. For example:
val gson = GsonBuilder().setLenient().create()
val myTranscriptions = myResponse.body!!.use {
val jsonReader = JsonReader(it.charStream())
jsonReader.isLenient = true
val transcriptions = mutableListOf<Status>()
while (jsonReader.peek() != JsonToken.END_DOCUMENT) {
transcriptions.add(gson.fromJson(jsonReader, Status::class.java))
}
transcriptions
}
Though, if the server continously provides status updates until processing is done, then maybe it would make more sense to directly process the parsed status instead of collecting them all in a list before processing them.
I think I am missing something. I have set up Full Calendar, and have the default version working, but now am adding my own JSON, and it is not.
Code in the calendar page is
$(document).ready(function() {
$('#calendar').fullCalendar({
header: {
left: 'prev,next today',
center: 'title',
right: 'month,agendaWeek,agendaDay,listWeek'
},
defaultDate: '2017-09-12',
editable: true,
navLinks: true, // can click day/week names to navigate views
eventLimit: true, // allow "more" link when too many events
events: {
url: 'php/get-events.php',
error: function() {
$('#script-warning').show();
}
},
loading: function(bool) {
$('#loading').toggle(bool);
}
});
});
I am learning how to encode JSON as I go along, and I found a tutorial online that gave me some code that seems to work. I have amended the original code in get-events.php to read like this (snippet with DB details taken out)...
// Require our Event class and datetime utilities
require dirname(__FILE__) . '/utils.php';
// Short-circuit if the client did not give us a date range.
if (!isset($_GET['start']) || !isset($_GET['end'])) {
die("Please provide a date range.");
}
// Parse the start/end parameters.
// These are assumed to be ISO8601 strings with no time nor timezone, like "2013-12-29".
// Since no timezone will be present, they will parsed as UTC.
$range_start = parseDateTime($_GET['start']);
$range_end = parseDateTime($_GET['end']);
// Parse the timezone parameter if it is present.
$timezone = null;
if (isset($_GET['timezone'])) {
$timezone = new DateTimeZone($_GET['timezone']);
}
class Emp {
public $id = "";
public $title = "";
public $start = "";
public $url = "";
}
while(!$JAN->atEnd()) {
e = new Emp();
$e->id = $JAN->getColumnVal("ID");
$e->title = $JAN->getColumnVal("TITLE");
$e->start = $JAN->getColumnVal("DATE")."T".$JAN->getColumnVal("TIME");
$e->url = "meeting_info.php?ID=".$JAN->getColumnVal("ID");
echo json_encode($e);
$JAN->moveNext();
}
$JAN->moveFirst(); //return RS to first record
// Read and parse our events JSON file into an array of event data arrays.
$json = file_get_contents(dirname(__FILE__) . '/../json/events.json');
$input_arrays = json_decode($json, true);
// Accumulate an output array of event data arrays.
$output_arrays = array();
foreach ($input_arrays as $array) {
// Convert the input array into a useful Event object
$event = new Event($array, $timezone);
// If the event is in-bounds, add it to the output
if ($event->isWithinDayRange($range_start, $range_end)) {
$output_arrays[] = $event->toArray();
}
}
// Send JSON to the client.
echo json_encode($output_arrays);
When I run the get-events.php page on it's own I get what I am assuming to be a correctly encoded JSON returned, one example in the array is ...
{"id":20,"title":"Executive Committee Meeting","start":"2017-05-01T00:00:00","url":"meeting_info.php?ID=20"}
Can anybody tell me what I have done wrong?
You need to run json_encode() on a complete array of PHP objects, not on each one individually. In your loop, add each Emp to an array, and then encode the array, when the loop ends.
If you look in your browser's network tab at the result of your ajax request, I think you're very likely to see a string of individual objects, but not wrapped in array (square) brackets, and not separated by commas, meaning the JSON is invalid. There's also a good chance there's an error message in your browser's console about the invalid data format. It's best to check this rather than assuming your JSON is correct. There are also online JSON validator tools you can paste it into, to validate the JSON in isolation.
Something like this should work better:
$events = array();
while(!$JAN->atEnd()) {
e = new Emp();
$e->id = $JAN->getColumnVal("ID");
$e->title = $JAN->getColumnVal("TITLE");
$e->start = $JAN->getColumnVal("DATE")."T".$JAN->getColumnVal("TIME");
$e->url = "meeting_info.php?ID=".$JAN->getColumnVal("ID");
$events[] = $e; //add event to the array
$JAN->moveNext();
}
echo json_encode($events); //encode the whole array as a coherent piece of JSON
//P.S. no need to run moveFirst really, since the request is going to end, and discard the resultset anyhow. Depending on your data access technique, you possibly need to close the recordset though, to avoid locking etc.
What you need your code to generate (and what fullCalendar is expecting), is a JSON array - here's a simple example containing 2 elements (representing events):
[
{ "id":20, "title":"Executive Committee Meeting", "start":"2017-05-01T00:00:00", "url":"meeting_info.php?ID=20" },
{ "id":21, "title":"Another Boring Committee Meeting", "start":"2017-05-02T00:00:00", "url":"meeting_info.php?ID=21" }
]
The example code I've given above should generate an array which is in the same format as this JSON sample.
How do I get the full message and not just the metadata using gmail api?
I have a service account and I am able to retrieve a message but only in the metadata, raw and minimal formats. How do I retrieve the full message in the full format? The following code works fine
var request = service.Users.Messages.Get(userId, messageId);
request.Format = UsersResource.MessagesResource.GetRequest.FormatEnum.Metadata;
Message message = request.Execute();
However, when I omit the format (hence I use the default format which is FULL) or I change the format to UsersResource.MessagesResource.GetRequest.FormatEnum.Full
I get the error: Metadata scope doesn't allow format FULL
I have included the following scopes:
https://www.googleapis.com/auth/gmail.readonly,
https://www.googleapis.com/auth/gmail.metadata,
https://www.googleapis.com/auth/gmail.modify,
https://mail.google.com/
How do I get the full message?
I had to remove the scope for the metadata to be able to get the full message format.
The user from the SO post have the same error.
Try this out first.
Go to https://security.google.com/settings/security/permissions
Choose the app you are working with.
Click Remove > OK
Next time, just request exactly which permissions you need.
Another thing, try to use gmailMessage.payload.parts[0].body.dataand to decode it into readable text, do the following from the SO post:
import org.apache.commons.codec.binary.Base64;
import org.apache.commons.codec.binary.StringUtils;
System.out.println(StringUtils.newStringUtf8(Base64.decodeBase64(gmailMessage.payload.parts[0].body.data)));
You can also check this for further reference.
try something like this
public String getMessage(string user_id, string message_id)
{
Message temp =service.Users.Messages.Get(user_id,message_id).Execute();
var parts = temp.Payload.Parts;
string s = "";
foreach (var part in parts) {
byte[] data = FromBase64ForUrlString(part.Body.Data);
s += Encoding.UTF8.GetString(data);
}
return s
}
public static byte[] FromBase64ForUrlString(string base64ForUrlInput)
{
int padChars = (base64ForUrlInput.Length % 4) == 0 ? 0 : (4 - (base64ForUrlInput.Length % 4));
StringBuilder result = new StringBuilder(base64ForUrlInput, base64ForUrlInput.Length + padChars);
result.Append(String.Empty.PadRight(padChars, '='));
result.Replace('-', '+');
result.Replace('_', '/');
return Convert.FromBase64String(result.ToString());
}
I've created a web server and this server is able to get POST request. However, when I send array of map[string]string in POST data, server receives it as array of interface{}. How can I convert it back to array of map[string]string?
Example : Like when I send following example in POST request,
params : [{"name" : "shail", "age" : 24}]
I'm sending params as
[](map[string]string)
but when server receives this data, it treats params as
[]interface{}
.How do I assign params in a variable defined by
[](map[string]interface{})
?
The easiest thing you can do is a type assertion on the values:
package main
import (
"fmt"
"reflect"
)
func main() {
var source []interface{}
var test = make(map[string]string, 0)
test["hello"] = "World"
source = append(source, test)
var dest = source[0].(map[string]string)
fmt.Println(reflect.TypeOf(dest).Kind())
fmt.Println(dest["hello"])
}
I use socket.io version 0.8.4
I have boiled down my problem to the following. I have data looking like this:
data.prop1 = [];
data.prop1.push("man");
data.prop2 = [];
data.prop2["hey"] = "man";
I send the data from the server to the client this way:
socket.emit("data", data);
On the client side I receive the data this way:
socket.on("data", function(data){ console.log(data); });
The weird thing is:
data.prop1 = [];
data.prop1.push("man"); // This data exists in the client side data object
data.prop2 = [];
data.prop2["hey"] = "man"; // This data does not exist.
data.prop2 is just an empty array on the client side.
Is there a known bug in json serializing arrays on the form in prop2?
Thankyou in advance
EDIT:
Problem solved using this workaround:
data.prop1 = [];
data.prop1.push("man");
data.prop2 = {}; // <= Object instead of array
data.prop2["hey"] = "man";
ECMA-262 about JSON.stringify:
The representation of arrays includes only the elements between zero and array.length – 1 inclusive. Named properties are excluded from the stringification.
Arrays are supposed to have numerical property names. So when the data.prop2 is transformed to JSON (which socket.io sends the data in, I imagine), it doesn't get the 'hey' property. If you want to use non-numerical property names, you should use objects instead of arrays:
data.prop1 = [];
data.prop1.push("man");
data.prop2 = {}; // Notice we're creating an object, not an array.
data.prop2["hey"] = "man"; // Alternatively: data.prop2.hey = "man"
Unfortunately, Javascript doesn't really work like that.
Check out this article, about half way down. It explains the problem where you try to set data.prop2["hey"] = "man";