Skip to content
New issue

Have a question about this project? # for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “#”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? # to your account

WebSocket close frame return type proposal discussion #1333

Open
MohamedSabthar opened this issue Feb 6, 2025 · 3 comments
Open

WebSocket close frame return type proposal discussion #1333

MohamedSabthar opened this issue Feb 6, 2025 · 3 comments

Comments

@MohamedSabthar
Copy link
Member

Please use this issue to discuss the websocket close frame return type proposal.

@gimantha
Copy link
Contributor

gimantha commented Feb 6, 2025

service class WsServiceUser {
*websocket:Service;

remote function onSubscribe(websocket:Caller caller, types:Subscribe sub) returns types:Response|error? {
    string? id = sub.id;
    if id is () {
        check caller->close(); // Send the close frame.
        return;
    }
    return {message: "System: Welcome to the chat!", event:"subscribe"};
} 

}

Is onSubscribe similar to onOpen? Or is it a function we introduce with this proposal?

@MohamedSabthar
Copy link
Member Author

Is onSubscribe similar to onOpen? Or is it a function we introduce with this proposal?

Yes, onSubscribe is a custom dispatcher, somewhat similar to onOpen. The Ballerina WebSocket module supports custom dispatchers, and you can learn more about them here. This proposal only introduces the CloseFrame record types.

@TharmiganK
Copy link

TharmiganK commented Feb 11, 2025

We have the status as a object type due to the following reasons:

  1. Distinguish anydata responses and CloseFrame responses
  2. Use distinct class with Status to make the type of status field different in the sub-types of CloseFrame. This makes sure that the user does not provide a different type value for status

I believe we can address (2) by using integer singleton types and for (1), we can use a new field called type. This approach has the following benefits:

  • No need for wrapping the code inside a object called status
  • No need to defined different status types for different close frames
  • When creating a custom close frame, we do not need to initialise the object field - status, we can just put the integer code

Sample:

import ballerina/io;

// Object type to identify the predefined close frame types
public readonly distinct class PredefinedCloseFrameType {
};

// Object type to identify the custom close frame types
public readonly distinct class CustomCloseFrameType {
};

// Constant to represent the predefined close frame types
public final PredefinedCloseFrameType PREDEFINED_CLOSE_FRAME = new;
// Constant to represent the custom close frame types
public final CustomCloseFrameType CUSTOM_CLOSE_FRAME = new;

// Private record represents the common fields of the close frames
type CloseFrameBase record {|
    readonly object {} 'type;
    readonly int code;
    anydata body;
|};

// Record to represent the normal closure close frame
public type NormalClosure record {|
    *CloseFrameBase;
    readonly PredefinedCloseFrameType 'type = PREDEFINED_CLOSE_FRAME;
    readonly 1000 code = 1000;
|};

// Record to represent the custom close frame
public type CustomCloseFrame record {|
    *CloseFrameBase;
    readonly CustomCloseFrameType 'type = CUSTOM_CLOSE_FRAME;
|};

// Close frame type
public type CloseFrame NormalClosure|CustomCloseFrame;

public function main() {
    NormalClosure normalClosure = {body: "Hello!"};
    io:println(getType(normalClosure));

    CustomCloseFrame customCloseFrame = {body: "Hello!", code: 2000};
    io:println(getType(customCloseFrame));
}

function getType(CloseFrame closeFrame) returns string =>
    closeFrame is CustomCloseFrame ? "custom" : (closeFrame is NormalClosure ? "normal" : "unknown");

# for free to join this conversation on GitHub. Already have an account? # to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants