WolfDan

WolfDan

Hello,

Actually I’m making a dynamic TCP protocol for a game with elixir, all the messages are already writed on another language I just need to handle every message in elixir and send back an answer to this message, actually my “model” to handle recieve its like this:

Get data bytes from the socket |> Read the message Id, the message length and main data |> contruct the message by reflection
(So here I decided to use a existing solution created by hanshine (It took me a long time to understand the code):

  1. Generate the messages at compile time based on a file, like this:
    McProtocol/lib/packet.ex at master · McEx/McProtocol · GitHub
  2. And get contruct it with the message id, like this:
    McProtocol/lib/packet/in.ex at master · McEx/McProtocol · GitHub
    )

But I also found a simplistic solution that is use Kernel.apply/3 and String.to_existing_atom/1, I’m not sure what of the two approach are better for this kind of problem (if you know a better solution feel free to tell me please).

After this “reflection” I need to call another reflection for handle the logic of this message and return the messages to send, the problem is that are so many messages sended by the client, to organize it I need many files to keep the project clean, so the project can looks like

handlers(folder)
   ->login(folder)
        |> login_handler.ex
   ->game(folder)
        |>fight(folder)
            |>fight_handler.ex
        |>inventory(folder)
        |>entities(folder)
.....

How I can handle this kind of reflection? For example call the by an id like this (I dont know if is a valid elixir code this is a code more like c#) (this is like call de definition by attribute, but I dont find something like this on elixir)

# handlers/connection/ping.ex
@messageid 1 #I dont know if its possible but its a code more like c#, so just need the message id and call with elixir in some way no matter the directory/module name(dunno if its possible)
def handle_ping_message(state, message) do
    {:send, PongMessage}
end

or like a pattern matching like this

# handlers/connection/ping.ex
def handle_ping_message(message = %{PingMessage}) do # sended as argument and pattern match over all proyect
   {:send, PongMessage}
end

Again, I don’t know if this is possible (or correct) in elixir, just I illustrate how it looks in my mind, I want to know how implement something like this on elixir

Thats my problem! I hope someone can help me to solve this and a way to improve the actual “solution” that I have

Greetings!

Showing Posts 1 to 5

peerreynders

peerreynders

Ok I can’t help but be reminded of this

@chadfowler
The older I get, the more I realize the biggest problem to solve in tech is to get people to stop making things harder than
they have to be.

… follow you so far but then …

I think you may be getting a bit hung up on the whole “reflection” business (always seemed a bit “smart aleck” to me anyway - if you want your code to be data use a Lisp) - and then as a result be possibly overcomplicating things.

Back in the dark ages when I was working in C this kind of problem was solved quite simply by:

  • Beginning the message with a fixed width discriminator field - i.e. the bit pattern in here identified the kind of message that it was. If you have lots of different types of messages you needed a wider field.
  • The second fixed width field would identify the total size of the message. While bytes as a unit would seem natural you could actually chose whatever unit you want - just be consistent.

So the size makes it possible to grab the entire message regardless of what the message actually contains and the discriminator is then used to select the appropriate dispatch function. The entire message is then simply handed to the correct dispatch function which

a) knows the internal structure of the message to extract the necessary information
b) knows where to dispatch this information to, in order to get it processed

Given the extensive support of binaries in Erlang I’m sure that there is plenty of Erlang code that operates in exactly the same way and that Elixir is quite capable of handling it. Also if the discriminators can be legally used as Map keys - you could load a map at runtime with discriminator/dispatch function pairs to select the correct dispatch function without writing a huge static case expression.

This is probably the biggest issue that you are facing - it sounds to me like your messages are being constructed “auto-magically” by some wizard based on some data structures as they exist in some source language. In the web services world this is called code first/contract last development - and it is bad news. Contract first/code last is always the way to go even if it is less convenient at first - design the messages first and independent of the implementation languages that may be used. Typically that is the best way to ensure that the messages are simply constructed and can be read in any implementation language.

To me this sounds you are still suffering from a “synchronous mindset” and because of it your design is having problems. Move towards an asynchronous processing model:

  • One part of the system is responsible for processing incoming messages. It’s only responsibility is to make sure that the incoming data is routed to the place that needs to process it. It is not concerned at all with any potential responses.

  • Once the data is processed it is routed to an entirely different part of the system which sends off the results (back?)

Essentially you need to start following Scott Wlaschin’s advice (“Thinking Functionally”) and move away from the request/response model of using functions and processes and think more in terms of input/output and “railway oriented” programming.

WolfDan

WolfDan OP

Thanks for your answer @peerreynders! I took all my time to explore every example, I need to say thanks help me to think more functinal (specially the monads), but sadly I need to say that I still without figure out a final Elixir way for my problem, I’ll explain:

Here is not a problem, I already have my reader/writer for every data over the socket, it basically contains:

  • Message id (unique id for every message, every one has a different work on the server and call for something different) [always an ushort field, integer if its elixir]
  • The message length
  • The rest data, this remain data is used to construct the “module” based on the MessageId, this “module” contains primitive properties and class properties as well (this work in a OO language, but this abstractions can easily move to elixir, simply moving the abstract class to the result module), so here…

…is the problem, the total messages in this case are 1040 without counting the types (Serialized classes inside de message) and the server sends 705 of those messages and recieve 335 from the client, handle the deserializer for all those messages + the handlers for every messages its insane exausting and hard to mantain!

This is an interesting proposal can you give me an example about it? I exactly dont understand what do you mean with “discriminators” on elixir

I’ll keep this in mind after solve the dispatch problem, thanks!


So in summary my problem is “how to construct a module based on a identifier without using a huge case expression (?)” and “how to call a handler (module function) based on this result module (or the message id) without using a huge case expression (again)”


Notes: I just give my previous examples based on my experience on C#, this is the “C# like” way to handle this solution, but now I’m really sure that this is not the solution for Elixir, so I want to know what is the best way here ^^ I did this project specifically to know the amazing Elixir ^^, this challenges are the best to study the language :smiley: (in my opinion ^^), I’m really happy to get answers that makes me learn more about Elixir, thanks!

Greetings!

peerreynders

peerreynders

Well, I think this is your first problem right here - why do you need such a large number of types or kinds of messages? I think it is time that you have a good look at your message protocol because it certainly sounds like it has gotten out of control some time ago.

WolfDan

WolfDan OP

Hahahaha sadly I can’t do it its already implemented, I cannot change nothing from this code, just code the server side ^^’

peerreynders

peerreynders

Ok, due to the inflexibility on this part - if you are doing this just as a learning experience - step back and walk away right now …

Because if you press forward you may have already noticed that there is nothing but an unrewarding exercise in utter frustration ahead of you - which isn’t going to be worth the effort for the “learning experience”. This has nothing to do the any lack of capability on Elixir’s part but everything with how the existing system has been designed to be irreversibly coupled with it’s initial implementation environment - most likely for the sake of a few shortcuts here and there that likely did not help the overall system design.

It is starting to sound a lot like these messages are simply conveyances for some arbitrary serialized object aggregates that can only work because both the client and the server were originally implemented on the same platform and language that enabled them to share an identical class hierarchy - causing the worst kind of implementation coupling.

Now if for some reason an “unrewarding exercise in utter frustration” is somehow the lesser of two evils, the DDD approach would be to create an anti-corruption-layer. But you would need to understand on a very fundamental non-Elixir or non-C# level what the actual essence of these 1040 “types” of messages actually boils down to - so that you can take that insanity and distill it down to some sanely structured information that you can make some sense out of. You will need this fundamental knowledge to build a “layer” the turns insanity into sanity.

Essentially your project seems to suffer from a problem that also came up in this topic - you cannot simply take an object-oriented solution implementation and start translating that implementation into Elixir - typically a solution redesign is required - not because Elixir isn’t good enough but because sadly many OO implementations let their OO ways leak into aspects where they are at best not beneficial or at worst extremely detrimental.

— All posts loaded —

Where Next? Top

Trending in Questions Top

stjefim
Hello! Suppose you are building workflow (order / task / payment) processing system with the following requirements: Each workflow con...
New
Blokh
Hey guys, I’ve got a huge CSV ( around 10 GB ) that needs to be processed hourly Do you guys have any suggestions what is the best prac...
New
roeland
Kia ora, We have been using elixir-google-api to connect to Google Drive. However, with the updates to Tesla due to CVEs this is now bro...
New
kszambelanczyk
Hello! Could someone please give me a help/sample code, how to delete a file from s3 using waffle/waffle_ecto from Phoenix app. I creat...
New
Onor.io
I have what I’ve heard referred to as a “lookup table” in my database. This is a way of assigning codes to common values. One common lo...
New
jaybe78
Hello, I’m developing a online persistent chat system (what’s app) like using elixir/dynamodb/aws for a mobile app(flutter). The diffic...
New
Trolleger
What approach to take when sending live updates to “random” users Hi! I have a question, I have a little chat app, and when I create a DM...
New

Other Trending Topics Top

garrison
Hobbes is a low-level distributed database for the Elixir programming language. Hobbes provides a simple, safe, and scalable storage lay...
New
jimsynz
Beam Bots (or just BB for short) is a framework for building fault-tolerant robotics applications in Elixir using familiar OTP patterns. ...
New
mcass19
ExRatatui lets you cook up rich terminal UIs in Elixir, powered by Rust’s ratatui via Rustler NIFs. Build interactive terminal applicatio...
New
netoum
Corex is an accessible, unstyled UI component library for Phoenix that integrates Zag.js state machines using Vanilla JavaScript and Live...
New
Damirados
Hello everyone. After busy few months I am happy to announce v0.1.0 of Emerge & Solve. They are GUI (Emerge) and State management (S...
New
wintermeyer
There are three potential reasons for members of this forum to have a look at https://vutuv.de You are tired or annoyed of LinkedIn. Yo...
New

We're in Beta

About us Mission Statement

Options

Thread Display Mode




Thread Preview

Skip Thread Previews