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

water
I’m aware of 2 such projects, are there others? git: GitHub - team-alembic/realworld: A fullstack Phoenix LiveView application with back...
New
katta
I having some trouble figuring out if I have set myself too strict of standards for my production server. Currently I can handle 75% of r...
New
peck
Hi everyone. My team and I have been working on a fairly modest app based around video streaming and chat, but we’ve landed a customer t...
New
bradley
I really like the adapter patterns that ecto, nebulex, waffle, etc. use and would love find something similar for a key management servic...
New
unaware8150
Hello folks! So at work, we are seeing some situations where we have to define some “fixed” strings that are used across the codebase in...
New
Alvinkariuki
How Can I Optimise Compile Time Dependencies I have been building an elixir application for about 2 years now. Many modules and files ha...
New

Other Trending Topics Top

budgie
A little off-topic, but I feel like people here have a good head on their shoulders. I used to be quite good at making software. Was luc...
New
KristerV
Hey. Is there anyone here who creates agents in their apps? Not talking about using agents, but creating them. I’m finding it pretty diff...
New
mudasobwa
I fully migrated to my own harness from Anthropic/Gemini and I think it’s time to share it. Welcome DSH, the DeepSeek Harness, fully writ...
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
juhalehtonen
There has been a thread to discuss the Stack Overflow Developer Survey on this forum every year since 2018, so here’s yet another one for...
New
budgie
I love Elixir. It’s one of 2 programming languages I’ve ever fallen in love with. But I don’t use it anymore. Serverless was the promis...
New

We're in Beta

About us Mission Statement

Options

Thread Display Mode




Thread Preview

Skip Thread Previews