markx
2018-8-1 21:58:08

Hi,


markx
2018-8-1 21:58:25

How do I append a byte to a bytes?


lexi.lambda
2018-8-1 22:02:00

(bytes-append bs (bytes b))


markx
2018-8-1 22:27:30

ah thanks.


markx
2018-8-2 01:00:52

> (char->integer (read-char (open-input-bytes (bytes 255)))) 65533


markx
2018-8-2 01:01:06

Why doesn’t it return 255?


andreiformiga
2018-8-2 01:07:02

maybe something to do with numeric conversions


andreiformiga
2018-8-2 01:07:23

255 is all 1’s in binary, which is –1 when interpreted as two’s complement (in 8 bits)


markx
2018-8-2 01:10:29

well, that still doesn’t explain why it doesn’t return 255.


markx
2018-8-2 01:13:02

So how can I make sure to read the 255 correctly?


notjack
2018-8-2 01:13:31

what does the read-char expression evaluate to?


markx
2018-8-2 01:14:12

#\�


notjack
2018-8-2 01:15:26

did a little digging: the unicode char with codepoint 255 is not represented with a single byte in utf8, it’s represented with two bytes - so a bytestring with just one byte of 255 is not a valid utf 8 string (which is the encoding that open-input-bytes uses)


notjack
2018-8-2 01:15:46

and I think 65533 is the codepoint for an unrecognized character


markx
2018-8-2 01:16:46

Ah that makes sense.


notjack
2018-8-2 01:17:07
> (bytes->list (string->bytes/utf-8 (string (integer->char 255))))
'(195 191)

markx
2018-8-2 01:17:30

so say if I have a bytes 97 109 101 58 32 255 249. How do I read the chars before 255 correctly?


notjack
2018-8-2 01:17:54

do you know that it’s utf 8 encoded?


markx
2018-8-2 01:19:03

I guess it’s not then. Actually, this is telnet data, in which 255 is a special cmd, instead of data.


notjack
2018-8-2 01:19:40

i have no idea how telnet works there ¯_(ツ)_/¯


markx
2018-8-2 01:19:43

so it’s normal utf8 chars, with some cmd bytes.


markx
2018-8-2 01:19:54

well, you don’t need to know…


markx
2018-8-2 01:20:25

yeah, that’s fine. I guess I’ll just have to read by byte, and then convert the utf8 bytes into chars.


notjack
2018-8-2 01:21:49

>All data octets except 0xff are transmitted over Telnet as is. (0xff, or 255 in decimal, is the IAC byte (Interpret As Command) which signals that the next byte is a telnet command. The command to insert 0xff into the stream is 0xff, so 0xff need to be escaped by doubling it when sending data over the telnet protocol.)


notjack
2018-8-2 01:23:05

hmm so yeah, guess you gotta turn your telnet-stream into a telnet-data-stream by ripping out each 255 and the byte after it, unless its a command that changes the meaning of the data like that “insert 255 into the stream” command


markx
2018-8-2 01:25:49

In my case it’s fine to just strip off all the 255s


notjack
2018-8-2 01:27:18

do you have access to some reusable code that decodes telnet streams? I think if you just strip out only the 255s you’ll still have leftover command bytes that will mess up utf8 decoding


markx
2018-8-2 01:28:28

Yeah you are right. I don’t have that. I was actually looking for some telnet lib in racket, but didn’t find any.


markx
2018-8-2 01:29:35

also ideally, I think I should have a function for tcp-input-port -> telnet-data-port , but I don’t know how to write this function for now.


notjack
2018-8-2 01:30:04

and I suspect writing a telnet implementation is not how you’d like to spend your wednesday evening


notjack
2018-8-2 01:31:09

markx
2018-8-2 01:31:23

hahaha. I don’t need a full telnet protocol. I just need to ignore all the cmds.


markx
2018-8-2 01:32:20

Do you have an idea how to wrap a tcp port into another port that skips the cmd bytes?


notjack
2018-8-2 02:12:13

@markx it’s tricky because some of the command bytes shouldn’t be stripped, for instance <cmd> 255 shouldn’t be stripped and should be replaced with 255 because command 255 means “insert byte 255 into the data stream”


notjack
2018-8-2 02:13:09

I suspect there are other commands that change the data stream and if you ignore those commands instead of actually interpreting them, you’ll garble the text output because bytes will be missing or incorrect during utf8 decoding


notjack
2018-8-2 02:14:34

is it possible for you to change the thing that’s actually sending these bytes to do something else? like open a tcp connection or a unix domain socket or something?


markx
2018-8-2 02:20:53

@notjack Sorry I don’t understand. Do you mean to change the thing not to use telnet?


markx
2018-8-2 02:27:23

I’m writing a MUD client, and don’t have control on the server… So I can’t change that. But it’s really fine. I can ignore the cmds for now. I can add support for cmds later if necessary.


markx
2018-8-2 02:29:52

currently my problem is that, I have the logic of skipping cmd bytes and normal data together, but I really want to separate them. Like I said, I think ideally I can make a decorator, that wraps the tcp input port and only output data bytes. But I’m not sure how to create such a decorator.


notjack
2018-8-2 02:35:50

@markx ah yeah I meant change the thing to not use telnet, but if it’s not your server then that’s a no-go


notjack
2018-8-2 02:37:04

as for a decorator, I think you could make that by using make-pipe


notjack
2018-8-2 02:37:49

basically, you take your raw input and you make a pipe, then you spawn a thread that reads the raw input, decodes it into command-less bytes, then writes it into the output end of the pipe


notjack
2018-8-2 02:37:59

then the input end of the pipe becomes your new wrapper input port


markx
2018-8-2 02:42:14

@notjack Ah sounds good. If I need to spawn a thread, I guess I can also use a channel instead of a pipe? What’s the advantage of using a pipe then?


notjack
2018-8-2 02:43:54

the make-pipe procedure returns an input-port? and an output-port? so you don’t have to change any code you’ve written that assumes its reading data from an input port


notjack
2018-8-2 02:44:18

but other than that, they’re pretty similar approaches


notjack
2018-8-2 02:44:45

you can think of make-pipe as implementing an input-output port pair using a buffered async channel under the hood


markx
2018-8-2 02:58:13

oh, I see. I’ll try that. thanks @notjack So much for a Wednesday night!


notjack
2018-8-2 02:59:23

don’t get too caught up :) sleep is good


greg
2018-8-2 03:03:43

@markx When I learned about pipes, it wasn’t obvious to me how to use them. I didn’t appreciate how to use Racket threads. Here’s an example: http://pasterack.org/pastes/22031


greg
2018-8-2 03:06:40

btw the (λ () __) can also be written as (lambda () __) or (thunk __), as you prefer.


markx
2018-8-2 03:07:07

@greg wow! did you just hand write this example for me? this is awesome!


greg
2018-8-2 03:07:59

Well I didn’t mean to do it all for you, and take the fun away. Maybe I should have changed the example more. :slightly_smiling_face:


greg
2018-8-2 03:08:37

It’s just, I found it freaky at first. I just start a thread and it runs…? That’s the part I wanted to emphasize.


markx
2018-8-2 03:10:23

haha, I’m actually comfortable with threads. I came with some Go experience, which also uses CSP for concurrency, so they are pretty similar.


greg
2018-8-2 03:11:58

Ah, cool. Very similar.


markx
2018-8-2 03:12:14

The hardest part of racket for me is maybe how to organize the code. I mean, I don’t have enough functional programming experience, and that’s what I’m trying to learn from racket.


markx
2018-8-2 03:13:12

oh, and how to setup emacs. haha because I’m a vim user.


greg
2018-8-2 03:13:17

Yeah, that takes awhile. For me coming from C, the “all the parentheses” wasn’t such a big deal, really. It was more, “How do I get anything done if I can’t loop and mutate a variable??”


markx
2018-8-2 03:15:38

I actually don’t understand why “all the parentheses” would be a problem at all. I see them the same as whitespace… Just a symbol to separate other tokens and make up the syntax.


markx
2018-8-2 03:17:00

yeah that, and what global vars and parameters should I use. If I use them too much, it feels wrong.


markx
2018-8-2 03:17:24

It’s more of a style and design problem.


notjack
2018-8-2 03:17:31

funnily enough I find that people coming to racket from java don’t have the “how do I do things without loops + mutation” problem as much, assuming they’ve gotten used to doing stuff with java 8 streams