How to "undo" `bytes()` encoding for a string? - python-3.x

In making a socket chat, I want to do certain behaviour depending on the message string.
"""
c is a client socket
RECV_SIZE is the receiving buffer size
"""
message = c.recv(RECV_SIZE)
if message == bytes("/quit", "utf8"):
# logic specific to quitting
This is using /quit as an example string. But is there a way to decode the message so I can access it in plain text? If message is printed, it's a garbled mess, I'd like to print the actual message decoded. Essentially I want the reverse of bytes(), or "unbytes" if that makes sense. So instead I would do something like:
message = unbytes(c.recv(RECV_SIZE), "utf8")
if message == "/quit":
# logic specific to quitting

You are looking for the decode() method for bytes.
message = c.recv(RECV_SIZE).decode('utf8')

Related

Python SocketHandler with plain text

I've set up a SocketHandler but noticed it creates a binary output. I checked the docs and saw that it calls the "makePickle" function to create a binary output from the message record. I use dictConfig() to configure logging.
What I'd like to have is a plain text log message sent out to a TCP server without any pickling. I have two ideas in mind:
Create a custom handler derived from SocketHandler and override makePickle to return the plain text message with the given formatter
Create a custom handler derived from StreamHandler and pass IP and port and initialize stream to be a TCP stream
I can't decide which one is the better solution. Can you guys help me out? Also, if there's any other, easier and more straightforward way to achieve this I'm open to it.
Thanks
If anyone has the same problem, I decided to create a custom handler based on Socket handler. Like so:
class PlainTextTcpHandler(handlers.SocketHandler):
""" Sends plain text log message over TCP channel """
def makePickle(self, record):
message = self.formatter.format(record) + "\r\n"
return message.encode()
And you can use this handler as any other default one.

gRPC: How to call a remote procedure with combination of static and stream parameters?

I'm trying to transfer a file using gRPC. I can send the data, broken into chunks, using gRPC stream. I'm looking for way to also transfer the filename with the data. I'm sure there is an obvious solution that I'm missing. But here are a few approaches that I can think of
Sending filename with each chunk, which as the obvious disadvantage of retransmitting the same data. The .proto file will look like
service KeyValueStore {
rpc upload (stream FileData) returns (UploadStatus) {}
}
message FileData {
string filename = 1;
bytes data = 2;
}
Sending the filename as the first chunk. The receiver will need to be aware of such encoding.
But I'm looking for a non-hacky solution.
I was hoping to have a solution like
service KeyValueStore {
rpc upload (FileName, stream FileData) returns (UploadStatus) {}
}
But it's not possible and also discouraged according to answer here
In general, is there a cleaner way to call a procedure with a combination of normal and stream parameters? or achieve the same effect?
The post you linked is correct. Your input will be a single protocol buffer and in general, it should be named something like "FooRequest". The same is true for the response object, which should be called something like "FooResponse". Decoupling the request and response objects from their contents will give you room to change your API in a backwards-compatible manner over time.
The fact that we don't support multiple request types is not a barrier in practice, because protos can be nested arbitrarily. Consider an API like this.
message FileData {
string filename = 1;
bytes data = 2;
}
message UploadRequest {
oneof payload {
string filename = 1;
FileData file_data = 2;
}
}
service KeyValueStore {
rpc upload (stream UploadRequest) returns (UploadResponse) {}
}
Of course, from the server's perspective, it is now possible for a misbehaving client to send a filename in the middle of the stream. Or, conversely, to start sending chunks of data without first sending a filename.
You could decide that a client must send a filename as the first message. Or perhaps it's okay as long as the filename is sent before the stream ends. Or perhaps sending the filename is entirely optional and not sending one will result in a default value for the filename.
Your decision on these points will be part of your API, but will not be enforced automatically by protobuf as an IDL. You'll need to explicitly handle these corner cases in your server code. Please remember though that, since these are API considerations, they should be written somewhere in your protobuf file. Do your very best to ensure that every message, RPC, and field has a clear and concise docstring.

Communication with Python and Supercollider through OSC

I'm trying to connect Python with Supercollider through OSC, but it's not working.
I'm using Python3 and the library osc4py3.
The original idea was to send a text word by word, but upon trying I realized the connection was not working.
Here's the SC code:
(
OSCdef.new(\texto,{
|msg, time, addr, port|
[msg, time, addr,port].postIn;
},
'/texto/supercollider',
n
)
)
OSCFunc.trace(true);
o = OSCFunc(\texto);
And here's the Python code:
osc_startup()
osc_udp_client("127.0.0.1", 57120, "supercollider")
## here goes a function called leerpalabras to separate words in rows.
with open("partitura.txt", "r") as f:
for palabra in leerpalabras(f):
msg = oscbuildparse.OSCMessage("/texto/supercollider", ",s", palabra)
osc_send(msg, "supercollider")
sleep(2)
osc_terminate()
I've also tried with this, to see if maybe there was something wrong with my for loop (with the startup, and terminate of course):
msg = oscbuildparse.OSCMessage("/texto/supercollider", ",s", "holis")
osc_send(msg, "supercollider")
I run the trace method on SC, nothing appears on the post window when I run the Python script on terminal, but no error appears on neither one of them, so I'm a bit lost on what I can test to make sure is getting somewhere.
It doesn't print on the SC post window, it just says OSCdef(texto, /texto/supercollider, nil, nil, nil).
When I run the SuperCollider piece of your example, and then run:
n = NetAddr("127.0.0.1", 57120);
n.sendMsg('/texto/supercollider', 1, 2, 3);
... I see the message printed immediately (note that you used postIn instead of postln, if you don't fix that you'll get an error instead of a printed message).
Like you, I don't see anything when I send via the Python library - my suspicion is that there's something wrong on the Python side? There's a hint in this response that you have to call osc_process() after sends, but that still doesn't work for me
You can try three things:
Run OSCFunc.trace in SuperCollider and watch for messages (this will print ALL incoming OSC messages), to see if your OSCdef is somehow not receiving messages.
Try a network analyzer like Packet Peeper (http://packetpeeper.org/) to watch network traffic on your local loopback network lo0. When I do this, I can clearly see messages sent by SuperCollider, but I don't see any of the messages I send from Python, even when I send in a loop and call osc_process().
If you can't find any sign of Python sending OSC packets, try a different Python library - there are many others available.
(I'm osc4py3 author)
osc4py3 store messages to send within internal lists and returns immediately. These lists are processed during osc_process() calls or directly by background threads (upon selected theading model).
So, if you have selected as_eventloop threading model, you need to call osc_process() some times, like:
…
with open("partitura.txt", "r") as f:
for palabra in leerpalabras(f):
msg = oscbuildparse.OSCMessage("/texto/supercollider", ",s", palabra)
osc_send(msg, "supercollider")
for missme in range(4):
osc_process()
sleep(0.5)
…
See doc: https://osc4py3.readthedocs.io/en/latest/userdoc.html#threading-model

Azure Logic App, can not send message to service Bus

The send message action always said
"Message Received could not be parsed and is null"
Error output
The input is json array.
Input information and data
Any suggestion?
Thank you
Figured it out.
Looks like sending a message to service bus requires the message content to be base64 encoded. Since content is a JSON, need to stringify it explicitly prior to encoding, i.e. use #encodeBase64(string(jsonContent))
Changing the content type to text/plain has the same effect, since in that case the content is treated as a string to begin with.

TCP Communication Behaviour

I am sending data asynchronously over a TCP Socket. I am currently connected to a SMSC simulator, on my local computer, just to check that all the packets are created correctly, before connecting to the real thing.
I am only sending a PDU once, and the SMSC receives it perfectly, and generates a response PDU and sends it back, but after that, an error Message pops up on the simulator specifying that it cannot receive 100 messages. The problem is that I only send it once, there is no loop running that constantly sends the messages, and I have debugged and checked that it send only once.
I Think that the problem might be with the creation of the PDU. I start by creating an byte array of size 1024, and then filling as necessary. When filled up, it does not use the entire space of the array. So I am thinking that when the simulator receives it, retrieves the data from the array, and then it reads the '0' bytes in the array after the actual data as a new message, since it gives me a response message saying that the data is not valid.
Is there anyway to avoid this, or am I just missing something here? According to me, when receiving value in byte array, you should only use the necessary encoding to retrieve the data, and the rest of the '0' bytes should be ignored?
Sorry if my question is vague.
The problem was indeed the 0bytes in the array.
I solved it by removing the 0 bytes from the array, after reading an article posted on Stack Overflow:
Here is the Solution:
private byte[] CleanArray(byte[] array)
{
int i = array.Length - 1;
while (array[i] == 0)
{
i--;
}
byte[] cleanedArray = new byte[i + 1];
Array.Copy(array, cleanedArray, i + 1);
return cleanedArray;
}

Resources