I am working in Unity trying to figure out the WWW class and access API from online-go.com
I get an error in the Debug.Log though. Additionally, the Debug on Line 58 just returns a blank string. I don't think I am fully understanding how to use WWW since this is the first time I am using it.
Necessary data rewind wasn't possible
UnityEngine.Debug:Log(Object)
<LoadWWW>c__Iterator0:MoveNext() (at Assets/OGS.cs:60)
using UnityEngine;
using System.Collections;
using System.Collections.Generic;
using System;
using System.IO;
using System.Net;
using System.Text;
//using System.Net.httpclient;
public class OGS : MonoBehaviour {
string generateAPIClient = "http://beta.online-go.com/developer";
string APIKey = "0c63a59dd17ec69a48af5d9dc8b4e956";
string requestUserToken = "oauth2/access_token";
string clientID = "";
string clientSecret = "";
string baseURL = "http://online-go.com/";
string url = "";
string username;
string password;
string POST;
List<Settings> settings;
// Use this for initialization
void Start () {
Debug.Log("Opened");
settings = new List<Settings>();
Load("Settings");
clientID = AssignSetting("clientID");
clientSecret = AssignSetting("clientSecret");
username = AssignSetting("username");
password = AssignSetting("password");
POST = string.Format( "client_id={0}&client_secret={1}&grant_type=password&username={2}&password={3}",
clientID, clientSecret, username, password);
url = baseURL + requestUserToken;
StartCoroutine("LoadWWW");
}
//Assign settings loaded to settings variables
string AssignSetting (string item) {
int position = -1;
for(int i=0;i<settings.Count;i++) {
if(settings[i].name == item){return settings[i].value;}
}
return string.Empty;
}
IEnumerator LoadWWW() {
byte[] byteArray = GetBytes(POST);
Dictionary<string,string> headers = new Dictionary<string,string>();
headers.Add("Content-Type", "application/x-www-form-urlencoded");
WWW text = new WWW(url, byteArray, headers);
yield return text;
byteArray = text.bytes;
string POSTResponse = GetString(byteArray);
Debug.Log(POSTResponse);
Debug.Log(text.responseHeaders);
Debug.Log(text.error);
}
static byte[] GetBytes(string str)
{
byte[] bytes = new byte[str.Length * sizeof(char)];
System.Buffer.BlockCopy(str.ToCharArray(), 0, bytes, 0, bytes.Length);
return bytes;
}
static string GetString(byte[] bytes)
{
char[] chars = new char[bytes.Length / sizeof(char)];
System.Buffer.BlockCopy(bytes, 0, chars, 0, bytes.Length);
return new string(chars);
}
private bool Load(string fileName)
{
// Handle any problems that might arise when reading the text
try
{
string line;
// Create a new StreamReader, tell it which file to read and what encoding the file
// was saved as
StreamReader theReader = new StreamReader(Application.dataPath + "/Resources/" + fileName + ".txt");
// Immediately clean up the reader after this block of code is done.
// You generally use the "using" statement for potentially memory-intensive objects
// instead of relying on garbage collection.
// (Do not confuse this with the using directive for namespace at the
// beginning of a class!)
using (theReader)
{
// While there's lines left in the text file, do this:
do
{
line = theReader.ReadLine();
if (line != null)
{
// Do whatever you need to do with the text line, it's a string now
// In this example, I split it into arguments based on comma
// deliniators, then send that array to DoStuff()
string[] entries = line.Split(':');
if (entries.Length > 0){
Settings newSetting = new Settings(entries[0], entries[1]);
settings.Add(newSetting);
}
}
}
while (line != null);
// Done reading, close the reader and return true to broadcast success
theReader.Close();
return true;
}
}
// If anything broke in the try block, we throw an exception with information
// on what didn't work
catch (Exception e)
{
Console.WriteLine("{0}\n", e.Message);
return false;
}
}
}
necessary data rewind wasn't possible mainly occurs when redirection is involved during the WWW call.
To fix this, make sure that the URL's you call are not redirecting you to another page in the process. Also it would be a good idea to have some error handling before you use the value.
// wait for the result
yield return text;
// Handle the error if there is any
if (!string.IsNullOrEmpty(text.error)) {
Debug.Log(text.error);
}
// Now do with POSTResponse whatever you want if there were no errors.
Related
I am trying to read sensor data into Unity. For that I am using a TCP Server on a ESP32 by sending the data in json.
I am now trying to parse the received data into a serializable object.
Currently I am reading data from the server until I receive the final "}" bracket as a very rudimentary check for valid json as a starting point.
Now this is where I can't find my error. I am starting a Thread in the class which runs in the background and is constantly reading the server for new values.
But somehow I can't successfully concatenate the string which should be checked for the "}" character.
My code so far:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using System;
using System.Net.Sockets;
using System.Threading;
[Serializable]
public class SensorData
{
public int capacity;
}
public class MugSensorRead : MonoBehaviour
{
TcpClient client = new TcpClient();
const string IP = "192.168.137.50";
const int PORT = 5000;
public SensorData sensorData;
public int capacity;
bool _threadRunning;
Thread _thread;
// Use this for initialization
void Start ()
{
client.Connect (IP, PORT);
_thread = new Thread (updateSensorData);
_thread.Start ();
}
// Update is called once per frame
void Update ()
{
capacity = sensorData.capacity;
}
void updateSensorData()
{
_threadRunning = true;
while (_threadRunning)
{
NetworkStream stream = client.GetStream ();
string jsonMsg = "";
bool validJson = false;
while (!validJson)
{
byte[] inStream = new byte[1024];
stream.Read (inStream, 0, 1024);
string jsonData = System.Text.Encoding.ASCII.GetString (inStream);
jsonMsg = string.Concat (jsonMsg, jsonData);
if (jsonMsg.Contains("}"))
{
validJson = true;
//This part here is executed, but when I print(jsonMsg), it just prints the character "{" which gets transmitted in the first segment
}
}
sensorData = JsonUtility.FromJson<SensorData> (jsonMsg);
}
_threadRunning = false;
}
void OnDisable()
{
if (_threadRunning)
{
_threadRunning = false;
_thread.Join ();
}
}
}
Can you spot my error? I'm just not able to see, where my code fails.
Your error is that you are not checking how many bytes the read returned and you are adding 0's as part of the string content.
This should be replaced:
while (!validJson)
{
byte[] inStream = new byte[1024];
stream.Read (inStream, 0, 1024);
string jsonData = System.Text.Encoding.ASCII.GetString (inStream);
jsonMsg = string.Concat (jsonMsg, jsonData);
if (jsonMsg.Contains("}"))
{
validJson = true;
//This part here is executed, but when I print(jsonMsg), it just prints the character "{" which gets transmitted in the first segment
}
}
This would be the correct code:
while (!validJson)
{
byte[] inStream = new byte[1024];
int bytesRead = stream.Read (inStream, 0, 1024);
string jsonData = System.Text.Encoding.ASCII.GetString (inStream, 0, bytesRead);
jsonMsg = string.Concat (jsonMsg, jsonData);
if (jsonMsg.Contains("}"))
{
validJson = true;
//This part here is executed, but when I print(jsonMsg), it just prints the character "{" which gets transmitted in the first segment
}
}
0's in the array get converted to string end bytes that's why you don't see the '}' char, because there are string end characters before.
i have a method that read some files and get hashes SHA1Managed and then compare it with other hashes from a list, how can i do this method on other thread?
public bool CheckFile(string file, string filehash)
{
if (File.Exists(file))
{
using (FileStream stream = File.OpenRead(file))
{
SHA1Managed sha = new SHA1Managed();
byte[] checksum = sha.ComputeHash(stream);
string sendCheckSum = BitConverter.ToString(checksum)
.Replace("-", string.Empty);
return sendCheckSum.ToLower() == filehash;
}
}
else return false;
}
If you just want to run it in a background thread you'd actually need to move the task creation up one level since your function returns a result. Depending on how the calling code works something like this might work for you.
var backgroundTask = Task.Factory.StartNew(() =>
{
var result = CheckFile("file", "filehash");
//do something with the result
});
Try by this codes:
public async Task<bool> CheckFile(string file, string filehash)
{
await Task.Run<bool>(()=> {
if (File.Exists(file))
{
using (FileStream stream = File.OpenRead(file))
{
SHA1Managed sha = new SHA1Managed();
byte[] checksum = sha.ComputeHash(stream);
string sendCheckSum = BitConverter.ToString(checksum)
.Replace("-", string.Empty);
return sendCheckSum.ToLower() == filehash;
}
}
else return false;
});
}
Here I have a class I've created for the purpose of sending text-files and images over a serial port:
public class SendItem
{
private byte[] bytes;
private string _fileName;
private string _extension;
private int bytesSin;
public string Extension
{
get { return _extension; }
set { _extension = value; }
}
public string FileName
{
get { return _fileName; }
set { _fileName = value; }
}
public byte[] Bytes
{
get { return bytes; }
set { bytes = value; }
}
public SendItem()
{
}
public void SendFile(SerialPort serialPort1)
{
if (serialPort1.IsOpen)
{
OpenFileDialog OFDialog = new OpenFileDialog();
OFDialog.Title = "Open File";
OFDialog.Filter = "Text Files (*.txt)" + "|*.txt|All files (*.*)|*.*";
OFDialog.InitialDirectory = #"C:\";
bool? userClickedOK = OFDialog.ShowDialog();
if (userClickedOK == true)
{
serialPort1.DiscardInBuffer();
string chosenFile = OFDialog.FileName;
string ext = Path.GetExtension(OFDialog.FileName);
_extension = ext;
byte[] data = File.ReadAllBytes(chosenFile);
SendItem newSendItem = new SendItem();
newSendItem._extension = ext;
newSendItem._fileName = System.IO.Path.GetFileNameWithoutExtension(chosenFile);
newSendItem.bytes = data;
byte[] view = newSendItem.Serialize();
string test = Convert.ToBase64String(data);
serialPort1.Write(newSendItem.Serialize(), 0, newSendItem.Serialize().Length);
//serialPort1.Write(data, 0, data.Length);
}
}
}
public override string ToString()
{
return string.Format("File: {0}{1}",_fileName, _extension);
}
}
There is quite a few redundant things in the SendFile method, but I ask that it would be ignored in favour of the following issue I keep on having.
Whenever I send a text file or just plain chat text from a textbox, the following block of code is executed without triggering the catch:
void _sPort_DataReceived(object sender, SerialDataReceivedEventArgs e)
{
SerialPort sp = (SerialPort)sender;
byte[] data = new byte[sp.BytesToRead];
string message = string.Empty;
sp.Read(data, 0, data.Length);
try
{
SendItem receivedObject = data.Deserialize<SendItem>();
File.WriteAllBytes(#"d:\" + receivedObject.FileName + receivedObject.Extension, receivedObject.Bytes);
message = "File has been recieved.";
sp.Write("File sent.");
}
catch (Exception exp)
{
errors = exp.Message;
message = Encoding.UTF8.GetString(data);
}
App.Current.Dispatcher.Invoke(new Action(() => _response.Add("Friend: " + message)));
}
The problem comes in when I try to send an image... It trigger the catch and gives the exception There is an error in XML document (5, 3870).
My serializer and deserializer I've written is as follow:
public static byte[] Serialize<T>(this T source)
{
XmlSerializer serializer = new XmlSerializer(typeof(T));
MemoryStream stream = new MemoryStream();
serializer.Serialize(stream, source);
byte[] buffer = stream.GetBuffer();
stream.Close();
return buffer;
}
public static T Deserialize<T>(this byte[] source)
{
XmlSerializer serializer = new XmlSerializer(typeof(T));
MemoryStream stream = new MemoryStream(source);
T result = (T)serializer.Deserialize(stream);
stream.Close();
return result;
}
Can anyone point out where I'm making my mistake? I've been debugging it for ages and I can't wrap my head around it.
**EDIT:
I am also including the serialised data for an image I tried to send, after looking at it, it appears my Byte might be too big for the serial port - is there any way to adjust this or allow the serial port to take all of the data sent over?
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
It may or may not be the whole problem, but this is definitely a problem:
byte[] buffer = stream.GetBuffer();
That's quite possibly returning more data than you want - because it's not limiting itself to the length of the stream. MemoryStream has the handy MemoryStream.ToArray method to simplify this:
public static byte[] Serialize<T>(this T source)
{
XmlSerializer serializer = new XmlSerializer(typeof(T));
MemoryStream stream = new MemoryStream();
serializer.Serialize(stream, source);
return stream.ToArray();
}
(There's no benefit from closing a MemoryStream that you've created like this - and if you did feel you needed to, you should use a using statement.)
Likewise your Deserialize method can be simplified to:
public static T Deserialize<T>(this byte[] source)
{
XmlSerializer serializer = new XmlSerializer(typeof(T));
return (T) serializer.Deserialize(new MemoryStream(source));
}
Given that you were effectively trying to deserialize "the XML document - and then probably a load of "blank" data, that may well be the issue.
EDIT: Now there's a second problem:
byte[] data = new byte[sp.BytesToRead];
string message = string.Empty;
sp.Read(data, 0, data.Length);
You're assuming that all of the data is ready to read in a single go. That won't be true if there's more data than the buffer size of the serial port. Instead, if you're trying to put multiple "messages" onto what is effectively a stream, you'll need to either indicate the end of a message (and keep reading until you find that) or write the length of the message before the message itself - then when reading, read that length and then make sure you read that many bytes.
This is a standard issue when you try to use a stream-oriented protocol as a message-oriented protocol.
You should use ToByteArray() instead of GetBuffer().
I'm new to C# and trying to get my head around why the code below isn't working. I've tried to make a custom class HtmlRequest that isn't static so can be instantiated as many times as required using HtmlRequest someVar = new HtmlRequest();
return sb is holding the value but it's not being returned to hmtmlString on the line htmlString = htmlReq.getHtml(uri).
I've tried putting Get{code ...return sb;} after public class HtmlRequest but can't get the correct syntax
public partial class MainWindow : DXWindow
{
private void GetLinks()
{
HtmlRequest htmlReq = new HtmlRequest();
Uri uri = new Uri("http://stackoverflow.com/");
StringBuilder htmlString = new StringBuilder();
htmlString = htmlReq.getHtml(uri); //nothing returned on htmlString
}
}
public class HtmlRequest
{
public StringBuilder getHtml(Uri uri)
{
// used to build entire input
StringBuilder sb = new StringBuilder();
// used on each read operation
byte[] buf = new byte[8192];
// prepare the web page we will be asking for
HttpWebRequest request = (HttpWebRequest)WebRequest.Create(uri);
// execute the request
HttpWebResponse response = (HttpWebResponse)request.GetResponse();
// we will read data via the response stream
Stream resStream = response.GetResponseStream();
string tempString = null;
int count = 0;
Do
{
// fill the buffer with data
count = resStream.Read(buf, 0, buf.Length);
// make sure we read some data
if (count != 0)
{
// translate from bytes to ASCII text
tempString = Encoding.ASCII.GetString(buf, 0, count);
// continue building the string
sb.Append(tempString);
}
}
while (count > 0); // any more data to read?
return sb;
}
}
If I put a breakpoint on return sb; then the variable is correct but is not returning it.
It's probably something really obvious, can someone explain why it's not working and how to fix it?
Thank you
Try using the value instead of immediately exiting the method. An optimized build won't save the return value if it isn't used.
No need for this:
StringBuilder htmlString = new StringBuilder();
htmlString = htmlReq.getHtml(uri);
It's enough to say:
StringBuilder htmlString = htmlReq.getHtml(uri);
You'd have to define nothing. Nothing means "null", "garbage", what? Is htmlString the object it used to be? Or maybe the function does not return at all? What is it?
I'm porting my published app in Windows Phone, to Win 8. While trying to write to the IsolatedStorage equivalent, ApplicationDataContainer, I get an exception. The exception says
Error : The size of the state manager setting has exceeded the limit
I'm not sure if this is the correct way of using the ApplicationDataContainer.
public void WriteToIsolatedStorage()
{
try
{
ApplicationDataContainer localSettings = ApplicationData.Current.LocalSettings;
ApplicationDataCompositeValue composite = new ApplicationDataCompositeValue();
if (localSettings.Containers.ContainsKey("LoveCycleSetting"))
{
localSettings.DeleteContainer("LoveCycleSetting");
}
composite["GetWeekStart"] = m_bWeekStart;
composite["iHistCount"] = m_iHistCount;
composite["dtHistory"] = this.DateTimeToString(m_dtHistory);
composite["avgCycleTime"] = m_iAvgCycleTime;
}
}
The exception occurs at the second last line. m_dtHistory is a string array of size 400. So does the ApplicationDataCompositeValue have a fixed size? Or do I have to write the m_dtHistory array into a file? Cuz in WindowsPhone I could directly write the array into the IsolatedStorageSettings.
It would be really helpful if someone could guide me on this or give links.
Alfah
Yes, ironically settings storage is easier on the phone than WinRT. You can just serialize to a file instead. Here is what I did (partially copied from the code already in SuspensionManager.cs), which works for both value and reference types.
internal static async Task<bool> SaveSetting(string Key, Object value)
{
var ms = new MemoryStream();
DataContractSerializer serializer = new DataContractSerializer(value.GetType());
serializer.WriteObject(ms, value);
await ms.FlushAsync();
// Uncomment this to preview the contents being written
/*char[] buffer = new char[ms.Length];
ms.Seek(0, SeekOrigin.Begin);
var sr = new StreamReader(ms);
sr.Read(buffer, 0, (int)ms.Length);*/
ms.Seek(0, SeekOrigin.Begin);
StorageFile file = await ApplicationData.Current.LocalFolder.CreateFileAsync(Key, CreationCollisionOption.ReplaceExisting);
using (Stream fileStream = await file.OpenStreamForWriteAsync())
{
await ms.CopyToAsync(fileStream);
await fileStream.FlushAsync();
}
return true;
}
// Necessary to pass back both the result and status from an async function since you can't pass by ref
internal class ReadResults
{
public bool Success { get; set; }
public Object Result { get; set; }
}
internal async static Task<ReadResults> ReadSetting<type>(string Key, Type t)
{
var rr = new ReadResults();
try
{
var ms = new MemoryStream();
DataContractSerializer serializer = new DataContractSerializer(t);
StorageFile file = await ApplicationData.Current.LocalFolder.GetFileAsync(Key);
using (IInputStream inStream = await file.OpenSequentialReadAsync())
{
rr.Result = (type)serializer.ReadObject(inStream.AsStreamForRead());
}
rr.Success = true;
}
catch (FileNotFoundException)
{
rr.Success = false;
}
return rr;
}
The name of each setting can be 255 characters in length at most. Each setting can be up to 8K bytes in size and each composite setting can be up to 64K bytes in size.
https://msdn.microsoft.com/library/windows/apps/windows.storage.applicationdata.localsettings.aspx
I read somewhere but lost the reference that the size is 64KB
public static void StoreConfig(string content)
{
IEnumerable<string> strs = Split(content, 2000);
int i = 1;
foreach(var s in strs)
{
AppLocalSettings.Values["test" + (i++)] = s;
}
AppLocalSettings.Values["test_count"] = i-1 +"";
}
public static string ReadConfig()
{
string s = "";
int count = Convert.ToInt32(AppLocalSettings.Values["test_count"]);
for(int i = 1; i<=count; i++)
{
s += Convert.ToString(AppLocalSettings.Values["test" + (i)]);
}
return s;
}