Guides

Check website status

Follow these simple steps to look into general settings like call limits, currency information, supported languages and more using the Deriv API:

  1. Import the API module: Load the DerivAPIBasic module to interact with the Deriv API.
  2. Setup WebSocket: Establish a WebSocket connection using the app_id for authentication.
  3. Initialize the API: Create an instance of DerivAPIBasic using the WebSocket connection.
  4. Handle API response: Define websiteStatusResponse to process the response, handle errors, and log website status.
  5. Request website status: Define getWebsiteStatus to send a request to the API for website status when called.
  6. Button event listener: Attach an event listener to a button to trigger the website status request with a click.
// Import DerivAPIBasic from the Deriv API package
import DerivAPIBasic from '@deriv/deriv-api/dist/DerivAPIBasic.js';

// Set the app ID for API authentication. Use 1089 for testing or replace it with your app's ID.
const app_id = 1089;

// Create a WebSocket connection to the Deriv server using the app_id for authentication
const connection = new WebSocket(`wss://ws.derivws.com/websockets/v3?app_id=${app_id}`);

// Initialize the API using the WebSocket connection
const api = new DerivAPIBasic({ connection });

// Function to handle the website status response
const handleWebsiteStatusResponse = async (response) => {
  const data = JSON.parse(response.data);

  // If there's an error in the response, log the error message and disconnect
  if (data.error) {
    console.error('Error:', data.error.message);
    await api.disconnect();
    return;
  }

  // If the message type is 'website_status', log the relevant details
  if (data.msg_type === 'website_status') {
    const websiteStatus = data.website_status;
    console.log('Website Status:', websiteStatus.site_status);
    console.log('Available Languages:', websiteStatus.supported_languages);
    console.log('Terms & Conditions Version:', websiteStatus.terms_conditions_version);
    console.log('Broker Codes:', websiteStatus.broker_codes);
  }

  // Remove the event listener after processing the response
  connection.removeEventListener('message', handleWebsiteStatusResponse);
};

// Function to request website status from the API
const requestWebsiteStatus = async () => {
  connection.addEventListener('message', handleWebsiteStatusResponse); // Add the event listener for response
  await api.websiteStatus(); // Send the website status request
};

// Check if running in a browser or Node.js environment
if (typeof document !== 'undefined') {
  // Add a button event listener in the browser environment
  const website_status_button = document.querySelector('#websiteStatus');
  if (website_status_button) {
    website_status_button.addEventListener('click', requestWebsiteStatus);
  }
} else {
  // If running in Node.js, directly call the function
  requestWebsiteStatus();
}

/*
 * Instructions to Run the Code on a Local Machine:
 * 1. Ensure Node.js is installed on your machine. Download it from https://nodejs.org/ if needed.
 * 2. Install required dependencies:
 *      - Run: `npm install @deriv/deriv-api ws`
 * 3. Save this code to a file, e.g., `connect.js`.
 * 4. Open a terminal and navigate to the directory where the file is saved.
 * 5. Run the code using Node.js:
 *      - Run: `node connect.js`
 *
 * In a browser environment:
 * - Save this code to a JavaScript file and link it to an HTML page with a button element:
 *   `<button id="websiteStatus">Check Website Status</button>`
 * - Open the HTML file in a browser, and click the button to check the website status.
 */
package src.main.java;

import org.java_websocket.client.WebSocketClient;
import org.java_websocket.handshake.ServerHandshake;
import java.net.URI;
import java.net.URISyntaxException;
import java.util.Timer;
import java.util.TimerTask;
import com.google.gson.JsonObject;

public class WebSocketExample {

    public static void main(String[] args) {
        try {
            // Replace with your app_id
            int app_id = 1089;
            String serverUri = "wss://ws.derivws.com/websockets/v3?app_id=" + app_id;

            // Initialize the WebSocket client
            WebSocketClient client = new WebSocketClient(new URI(serverUri)) {

                @Override
                public void onOpen(ServerHandshake handshakedata) {
                    System.out.println("[open] Connection established");

                    // Send website status request
                    JsonObject websiteStatusRequest = new JsonObject();
                    websiteStatusRequest.addProperty("website_status", 1);
                    send(websiteStatusRequest.toString());
                    System.out.println("[sent] Website status request sent");

                    // Schedule a ping every 30 seconds
                    Timer timer = new Timer();
                    timer.scheduleAtFixedRate(new TimerTask() {
                        @Override
                        public void run() {
                            JsonObject pingMessage = new JsonObject();
                            pingMessage.addProperty("ping", 1);
                            send(pingMessage.toString());
                            System.out.println("[ping] Ping sent to keep connection alive");
                        }
                    }, 0, 30000);
                }

                @Override
                public void onMessage(String message) {
                    System.out.println("[message] Received: " + message);

                    JsonObject data = new com.google.gson.JsonParser().parse(message).getAsJsonObject();
                    if (data.has("error")) {
                        System.out.println("[error] " + data.getAsJsonObject("error").get("message").getAsString());
                    } else if ("website_status".equals(data.get("msg_type").getAsString())) {
                        JsonObject websiteStatus = data.getAsJsonObject("website_status");
                        String siteStatus = websiteStatus.get("site_status").getAsString();
                        System.out.println("Website Status: " + siteStatus);
                    } else if ("ping".equals(data.get("msg_type").getAsString())) {
                        System.out.println("[ping] Ping response received.");
                    }
                }

                @Override
                public void onClose(int code, String reason, boolean remote) {
                    System.out.println("[close] Connection closed by " + (remote ? "server" : "client") + ": " + reason);
                }

                @Override
                public void onError(Exception ex) {
                    System.out.println("[error] " + ex.getMessage());
                }
            };

            client.connect();

        } catch (URISyntaxException e) {
            System.out.println("[error] Invalid URI: " + e.getMessage());
        }
    }
}

/*
Instructions to run the code:

1. Ensure that Java is installed on your machine. You can download it from https://www.oracle.com/java/technologies/javase-jdk11-downloads.html.
2. Add the following dependencies to your project:
   - `java-websocket` for WebSocket functionality
   - `gson` for JSON handling

   If you are using Maven, add these dependencies to your `pom.xml`:

   <dependency>
       <groupId>org.java-websocket</groupId>
       <artifactId>Java-WebSocket</artifactId>
       <version>1.5.2</version>
   </dependency>
   <dependency>
       <groupId>com.google.code.gson</groupId>
       <artifactId>gson</artifactId>
       <version>2.8.8</version>
   </dependency>

3. Compile the code:
   javac WebSocketExample.java

4. Run the code:
   java WebSocketExample

Note: Replace `app_id` with your actual app_id if needed.


 */
#!/usr/bin/env perl
use strict;
use warnings;
use v5.014;
use AnyEvent;
use AnyEvent::WebSocket::Client;
use JSON;

# WebSocket URL and app_id
my $app_id = 1089;
my $url = "wss://ws.derivws.com/websockets/v3?app_id=$app_id";

# Create WebSocket client and connection
my $client = AnyEvent::WebSocket::Client->new;
$| = 1;  # Flush output immediately for real-time logging

# Function to send a website status request
sub send_website_status {
    my $connection = shift;
    my $website_status_request = encode_json({ website_status => 1 });
    $connection->send($website_status_request);
    say "[status] Website status request sent.";
}

# Establish WebSocket connection
$client->connect($url)->cb(sub {
    my $connection = eval { shift->recv };
    if (!$connection) {
        die "Connection error: $@";
    }
    say "[status] WebSocket connection established.";

    # Send website status request immediately
    send_website_status($connection);

    # Set a timeout for receiving a response
    my $timeout = AnyEvent->timer(
        after => 10,
        cb    => sub {
            say "[error] No response received within 10 seconds. Closing connection.";
            $connection->close;
        }
    );

    # Handle incoming messages
    $connection->on(each_message => sub {
        my ($connection, $message) = @_;

        # Cancel timeout upon receiving a message
        undef $timeout;

        my $data = eval { decode_json($message->body) };
        if ($@) {
            say "[error] Failed to decode JSON: $@";
            return;
        }

        # Handle errors
        if ($data->{error}) {
            say "[error] " . $data->{error}{message};
            $connection->close;
            return;
        }

        # Handle website status response
        if ($data->{msg_type} && $data->{msg_type} eq 'website_status') {
            my $website_status = $data->{website_status};
            say "Site Status: " . ($website_status->{site_status} // 'Unknown');
            say "Supported Languages: " . join(", ", @{$website_status->{supported_languages}});
            $connection->close; # Close connection after processing the response
        }
    });

    # Handle connection close
    $connection->on(finish => sub {
        say "[status] WebSocket connection closed.";
    });
});

# Start the AnyEvent event loop
AnyEvent->condvar->recv;

# Instructions to run the code on a local machine:
# 1. Ensure you have Perl installed on your machine.
# 2. Install the necessary Perl modules using the following commands:
#      cpanm AnyEvent AnyEvent::WebSocket::Client JSON
#    If `cpanm` is not installed, install it using `cpan App::cpanminus`.
# 3. Save this script to a file, e.g., `connect.pl`.
# 4. Run the script using the command:
#      perl connect.pl
# This script will connect to the Deriv WebSocket API, request the website status, and print the response.
<?php

require 'vendor/autoload.php';

use WebSocket\Client;

// Replace with your app_id
$app_id = 1089;
$uri = "wss://ws.derivws.com/websockets/v3?app_id=$app_id";

// Create a new WebSocket client
$client = new Client($uri);

try {
    echo "[open] WebSocket connection established.\n";

    // Send a website status request
    $website_status_request = json_encode(["website_status" => 1]);
    $client->send($website_status_request);
    echo "[sent] Website status request sent.\n";

    // Ping function to keep connection alive
    $ping_interval = 30; // in seconds
    $last_ping_time = time();

    // Main loop to handle responses and send ping messages
    while (true) {
        // Check if it's time to send a ping
        if (time() - $last_ping_time >= $ping_interval) {
            $client->send(json_encode(["ping" => 1]));
            echo "[ping] Ping sent to keep connection alive.\n";
            $last_ping_time = time();
        }

        // Receive response from WebSocket
        $response = $client->receive();
        $data = json_decode($response, true);

        if (isset($data["error"])) {
            echo "[error] " . $data["error"]["message"] . "\n";
            break;
        } elseif ($data["msg_type"] === "website_status") {
            $website_status = $data["website_status"];

            // Print important information from the website status
            echo "[status] Website Status:\n";
            echo "  - Site Status: " . ($website_status["site_status"] ?? "N/A") . "\n";
            echo "  - Supported Languages: " . implode(", ", $website_status["supported_languages"] ?? []) . "\n";

            // Extract and print currency information
            echo "  - Currencies Config:\n";
            foreach ($website_status["currencies_config"] ?? [] as $currency => $config) {
                echo "    * {$currency} ({$config['name']}):\n";
                echo "      - Type: " . ($config["type"] ?? "N/A") . "\n";
                echo "      - Fractional Digits: " . ($config["fractional_digits"] ?? "N/A") . "\n";
                echo "      - Deposit Suspended: " . ($config["is_deposit_suspended"] ? "Yes" : "No") . "\n";
                echo "      - Withdrawal Suspended: " . ($config["is_withdrawal_suspended"] ? "Yes" : "No") . "\n";
            }

            echo "[status] End of Website Status Response.\n";
        } elseif ($data["msg_type"] === "ping") {
            echo "[ping] Ping response received.\n";
        }

        // Sleep briefly to prevent continuous loop
        usleep(500000); // 500ms
    }

    // Close the WebSocket connection
    $client->close();
    echo "[close] WebSocket connection closed.\n";

} catch (Exception $e) {
    echo "[error] " . $e->getMessage() . "\n";
}

/*
Instructions to run the code:

1. Ensure PHP is installed on your machine. You can download it from https://www.php.net/.
2. Install Composer if you haven't already, by downloading it from https://getcomposer.org/.
3. Create a `composer.json` file in the same directory as your PHP script with the following content:

   {
     "require": {
       "textalk/websocket": "^1.5"
     }
   }

4. Run the following command to install the WebSocket library:

   composer install

5. Save the code above to a PHP file, e.g., `website_status_client.php`.
6. Run the code from the command line:

   php website_status_client.php

Note: Replace `app_id` with your actual app_id if needed.
*/
import asyncio
from deriv_api import DerivAPI

# Replace with your actual app_id
app_id = 1089

async def main():
    # Initialize the DerivAPI instance
    api = DerivAPI(app_id=app_id)

    try:
        # Send a website status request
        website_status_request = {"website_status": 1}
        response = await api.send(website_status_request)
        print("Website status request sent")

        # Process the response and print important information
        print_website_status(response)

        # Function to send a ping every 30 seconds to keep the connection alive
        async def keep_alive():
            while True:
                await api.ping()  # Send a ping message
                print("Sent ping to keep connection alive")
                await asyncio.sleep(30)  # Ping every 30 seconds

        # Run the keep-alive ping loop
        await asyncio.gather(keep_alive())

    except Exception as e:
        print(f"An error occurred: {e}")

    finally:
        # Disconnect from the API
        await api.disconnect()
        print("Disconnected from Deriv API")

# Helper function to format and print website status details
def print_website_status(response):
    data = response.get("website_status", {})
    if data:
        print("[Website Status]")
        print(f"  - Site Status: {data.get('site_status', 'N/A')}")
        print("  - Supported Languages:", ", ".join(data.get("supported_languages", [])))

        # Display currency configurations
        currencies_config = data.get("currencies_config", {})
        print("  - Currencies Config:")
        for currency, config in currencies_config.items():
            print(f"    * {currency} ({config.get('name', 'N/A')}):")
            print(f"      - Type: {config.get('type', 'N/A')}")
            print(f"      - Fractional Digits: {config.get('fractional_digits', 'N/A')}")
            print(f"      - Deposit Suspended: {'Yes' if config.get('is_deposit_suspended') else 'No'}")
            print(f"      - Withdrawal Suspended: {'Yes' if config.get('is_withdrawal_suspended') else 'No'}")
        print("[End of Website Status Response]")

# Run the main function
if __name__ == "__main__":
    asyncio.run(main())

# Instructions to run the code:
# 1. Ensure Python is installed on your machine (https://www.python.org/downloads/).
# 2. Install the Deriv API package by running:
#      pip install deriv_api
# 3. Save this code to a file, e.g., `website_status_client.py`.
# 4. Run the code from the command line:
#      python website_status_client.py
#
# This script will connect to Deriv’s WebSocket API, request the website status, and send pings every 30 seconds to keep the connection alive.
# The response includes important details about the website status and configuration for each currency.
use tokio_tungstenite::connect_async;
use tokio_tungstenite::tungstenite::protocol::Message;
use futures_util::{SinkExt, StreamExt};
use tokio::{sync::Mutex, task::spawn};
use std::sync::Arc;
use serde_json::json;
use url::Url;

#[tokio::main]
async fn main() {
    let app_id = 1089;
    let url = format!("wss://ws.derivws.com/websockets/v3?app_id={}", app_id);
    let url = Url::parse(&url).expect("Invalid URL");

    // Connect to the WebSocket server and wrap `socket` in Arc<Mutex<_>>
    let (socket, _) = connect_async(url).await.expect("Failed to connect");
    let socket = Arc::new(Mutex::new(socket));

    println!("[status] WebSocket connection established");

    // Website status request JSON
    let website_status_request = json!({
        "website_status": 1
    });

    // Clone `socket` to send the website status request
    let send_socket = Arc::clone(&socket);
    let send_task = spawn(async move {
        let mut socket = send_socket.lock().await;
        if socket.send(Message::Text(website_status_request.to_string())).await.is_ok() {
            println!("[status] Website status request sent.");
        }
    });

    // Task to handle incoming messages
    let receive_socket = Arc::clone(&socket);
    let receive_task = spawn(async move {
        let mut socket = receive_socket.lock().await;
        while let Some(Ok(msg)) = socket.next().await {
            match msg {
                Message::Text(text) => {
                    let data: serde_json::Value = serde_json::from_str(&text).unwrap_or_else(|_| json!({}));
                    if data.get("msg_type").unwrap_or(&json!("")) == "website_status" {
                        println!("[Website Status] Site Status: {}", data["website_status"]["site_status"]);
                        let supported_languages: Vec<String> = data["website_status"]["supported_languages"]
                            .as_array()
                            .unwrap_or(&vec![])
                            .iter()
                            .filter_map(|lang| lang.as_str().map(|s| s.to_string()))
                            .collect();
                        println!("Supported Languages: {:?}", supported_languages);
                    } else if let Some(error) = data.get("error") {
                        println!("[Error] {}", error["message"]);
                    }
                }
                _ => {}
            }
        }
    });

    // Await all tasks to complete
    let _ = tokio::try_join!(send_task, receive_task);

    // Close the WebSocket connection
    let mut socket = socket.lock().await;
    socket.close(None).await.expect("Failed to close connection");
    println!("[close] Connection closed.");
}

/*
Instructions to run the code:

1. Ensure Rust and Cargo are installed on your machine. You can download them from https://www.rust-lang.org/.
2. Add the necessary dependencies to `Cargo.toml`:

   [dependencies]
   tokio = { version = "1", features = ["full"] }
   tokio-tungstenite = "0.16"
   futures-util = "0.3"
   serde_json = "1.0"
   url = "2.2"

3. Build the project:

   cargo build --release

4. Run the project:

   cargo run --release

This code will connect to the Deriv WebSocket API, request the website status, print the website's status, supported languages, and handle any potential errors in the response.
*/
import Foundation

// Make webSocketTask a global variable to keep the connection open
var webSocketTask: URLSessionWebSocketTask?

// Function to create and handle WebSocket connection
func connectWebSocket() {
    let appID = 1089 // Replace with your app_id.
    let url = URL(string: "wss://ws.derivws.com/websockets/v3?app_id=\(appID)")! // WebSocket URL with the app_id
    let request = URLRequest(url: url)
    
    // Initialize webSocketTask with URLSession
    webSocketTask = URLSession.shared.webSocketTask(with: request)
    
    // Start the WebSocket connection
    webSocketTask?.resume()
    print("[status] WebSocket connection established.")
    
    // Function to send website status request
    func sendWebsiteStatusRequest() {
        let websiteStatusRequest = ["website_status": 1] as [String: Any]
        
        if let requestData = try? JSONSerialization.data(withJSONObject: websiteStatusRequest, options: []) {
            let message = URLSessionWebSocketTask.Message.data(requestData)
            webSocketTask?.send(message) { error in
                if let error = error {
                    print("[error] Failed to send website status request: \(error.localizedDescription)")
                } else {
                    print("[status] Website status request sent.")
                }
            }
        }
    }
    
    // Function to receive messages from the server
    func receiveMessage() {
        webSocketTask?.receive { result in
            switch result {
            case .success(let message):
                switch message {
                case .string(let text):
                    if let data = text.data(using: .utf8),
                       let json = try? JSONSerialization.jsonObject(with: data, options: []) as? [String: Any] {
                        handleServerMessage(json)
                    }
                case .data(let data):
                    print("[message] Binary data received: \(data)")
                @unknown default:
                    print("[message] Received unknown message type")
                }
                
                // Continue to receive messages
                receiveMessage()
                
            case .failure(let error):
                print("[error] Failed to receive message: \(error.localizedDescription)")
            }
        }
    }
    
    // Function to handle the website status response from server
    func handleServerMessage(_ data: [String: Any]) {
        if let error = data["error"] as? [String: Any], let message = error["message"] as? String {
            print("[Error] \(message)")
        } else if data["msg_type"] as? String == "website_status", let websiteStatus = data["website_status"] as? [String: Any] {
            let siteStatus = websiteStatus["site_status"] as? String ?? "Unknown"
            let supportedLanguages = websiteStatus["supported_languages"] as? [String] ?? []
            
            print("[Website Status] Site Status: \(siteStatus)")
            print("[Website Status] Supported Languages: \(supportedLanguages.joined(separator: ", "))")
        }
    }
    
    // Send the website status request and start receiving messages
    sendWebsiteStatusRequest()
    receiveMessage()
}

// Function to close the WebSocket connection
func closeWebSocketConnection() {
    webSocketTask?.cancel(with: .normalClosure, reason: nil)
    print("[close] Connection closed cleanly")
}

// Start WebSocket connection
connectWebSocket()

// Keep the program running to wait for messages
RunLoop.main.run()

/*
Instructions to run the code:

1. Ensure Swift is installed on your machine. You can use Xcode or install the Swift toolchain from https://swift.org/.
2. Create a new Swift file (e.g., `WebSocketClient.swift`) and paste the code above.
3. Open a terminal and navigate to the directory where the file is saved.
4. Run the code with the following command:

   swift WebSocketClient.swift

5. The program will connect to the Deriv WebSocket API, request the website status, and print the site's operational status and supported languages.
6. To stop the program, press `Ctrl+C` in the terminal.

Note: Replace `app_id` with your actual app_id if required.
*/
using System;
using System.Net.WebSockets;
using System.Text;
using System.Text.Json;
using System.Threading;
using System.Threading.Tasks;

class WebSocketExample
{
    private static readonly Uri uri = new Uri("wss://ws.derivws.com/websockets/v3?app_id=1089"); // Replace with your app_id if needed

    public static async Task Main(string[] args)
    {
        using (ClientWebSocket webSocket = new ClientWebSocket())
        {
            Console.WriteLine("Attempting to connect to WebSocket...");

            await webSocket.ConnectAsync(uri, CancellationToken.None);
            Console.WriteLine("[status] WebSocket connection established.");

            // Send website status request
            await SendWebsiteStatusRequest(webSocket);

            // Handle responses from the server
            await HandleResponses(webSocket);
        }
    }

    private static async Task SendWebsiteStatusRequest(ClientWebSocket webSocket)
    {
        var websiteStatusRequest = new { website_status = 1 };

        string requestJson = JsonSerializer.Serialize(websiteStatusRequest);
        var bytes = Encoding.UTF8.GetBytes(requestJson);
        await webSocket.SendAsync(new ArraySegment<byte>(bytes), WebSocketMessageType.Text, true, CancellationToken.None);
        Console.WriteLine("[status] Website status request sent.");
    }

 private static async Task HandleResponses(ClientWebSocket webSocket)
 {
     var buffer = new byte[8192]; // Increased buffer size

     while (webSocket.State == WebSocketState.Open)
     {
         var result = await webSocket.ReceiveAsync(new ArraySegment<byte>(buffer), CancellationToken.None);

         if (result.MessageType == WebSocketMessageType.Close)
         {
             Console.WriteLine("WebSocket connection closed by server.");
             await webSocket.CloseAsync(WebSocketCloseStatus.NormalClosure, "Closing", CancellationToken.None);
         }
         else
         {
             // Append received bytes to a string builder
             var response = Encoding.UTF8.GetString(buffer, 0, result.Count);
             var data = JsonDocument.Parse(response).RootElement;

             // Check for "error" in the response
             if (data.TryGetProperty("error", out var error))
             {
                 Console.WriteLine($"[Error] {error.GetProperty("message").GetString()}");
                 await webSocket.CloseAsync(WebSocketCloseStatus.NormalClosure, "Closing due to error", CancellationToken.None);
                 break;
             }

             // Process the "msg_type" property
             if (data.TryGetProperty("msg_type", out var msgType) && msgType.GetString() == "website_status")
             {
                 var websiteStatus = data.GetProperty("website_status");
                 Console.WriteLine("Site Status: " + websiteStatus.GetProperty("site_status").GetString());
                 Console.WriteLine("Supported Languages: " + websiteStatus.GetProperty("supported_languages").ToString());
             }
         }
     }
 }
}

/*
Instructions to run the code locally:

1. Ensure you have .NET SDK installed. You can download it from https://dotnet.microsoft.com/download.

2. Save the code to a file named `WebSocketExample.cs`.

3. Open a terminal in the directory containing `WebSocketExample.cs`.

4. If using the .NET CLI, you can run the code with:
   - `dotnet new console -o WebSocketExample` (if creating a new project)
   - Move `WebSocketExample.cs` into the project directory `WebSocketExample`.
   - Navigate to the project directory: `cd WebSocketExample`.
   - Run `dotnet add package System.Net.WebSockets.Client` to add the WebSocket client dependency.
   - Run the code: `dotnet run`.

5. Alternatively, you can use an IDE like Visual Studio to create a console application, add the `System.Net.WebSockets.Client` package, and then run the application.

6. Replace `app_id=1089` in the URL with your actual app_id if needed.
*/
#include <libwebsockets.h>
#include <jansson.h>  // For JSON parsing
#include <string.h>
#include <signal.h>
#include <time.h>
#include <stdlib.h>

// Set up WebSocket context and connection details
static struct lws_context *context;
static int interrupted = 0, port = 443, ssl_connection = LCCSCF_USE_SSL;
static const char *server_address = "ws.derivws.com";
static const char *path = "/websockets/v3?app_id=1089";
static const char *pro = "lws-minimal-client";

// Interval for the ping in seconds
static const int ping_interval = 30;
static time_t last_ping_time = 0;

// Buffer to accumulate received message fragments
static char message_buffer[16384];
static size_t message_length = 0;

// Signal handler for graceful shutdown
static void sigint_handler(int sig) {
    interrupted = 1;
}

// Function to send a ping message
void send_ping(struct lws *wsi) {
    const char *ping_msg = "{\"ping\": 1}";
    unsigned char buf[LWS_PRE + 20];
    memcpy(&buf[LWS_PRE], ping_msg, strlen(ping_msg));
    lws_write(wsi, &buf[LWS_PRE], strlen(ping_msg), LWS_WRITE_TEXT);
    lwsl_user("Ping sent\n");
}

// Function to send a website status request
void send_website_status_request(struct lws *wsi) {
    const char *website_status_msg = "{\"website_status\": 1}";
    unsigned char buf[LWS_PRE + 128];
    memcpy(&buf[LWS_PRE], website_status_msg, strlen(website_status_msg));
    lws_write(wsi, &buf[LWS_PRE], strlen(website_status_msg), LWS_WRITE_TEXT);
    lwsl_user("Website status request sent\n");
}

// Function to check if JSON is complete based on braces balance
int is_json_complete(const char *json) {
    int brace_count = 0;
    for (size_t i = 0; json[i] != '\0'; i++) {
        if (json[i] == '{') brace_count++;
        else if (json[i] == '}') brace_count--;
    }
    return brace_count == 0;
}

// Function to handle the JSON response once fully received
static void handle_website_status_response(const char *response) {
    json_t *root;
    json_error_t error;

    // Parse the JSON response
    root = json_loads(response, 0, &error);
    if (!root) {
        printf("Error parsing JSON: %s at line %d, column %d\n", error.text, error.line, error.column);
        return;
    }

    // Check if the response contains an error
    json_t *error_obj = json_object_get(root, "error");
    if (error_obj) {
        const char *error_message = json_string_value(json_object_get(error_obj, "message"));
        printf("Error: %s\n", error_message);
        json_decref(root);
        return;
    }

    // Check if the message type is "website_status"
    const char *msg_type = json_string_value(json_object_get(root, "msg_type"));
    if (msg_type && strcmp(msg_type, "website_status") == 0) {
        json_t *website_status = json_object_get(root, "website_status");
        if (website_status) {
            const char *site_status = json_string_value(json_object_get(website_status, "site_status"));
            printf("Website Status: %s\n", site_status);
        }
    } else if (msg_type && strcmp(msg_type, "ping") == 0) {
        printf("Ping response received.\n");
    }

    json_decref(root);
}

// Callback function for WebSocket events
static int callback_minimal(struct lws *wsi, enum lws_callback_reasons reason,
                            void *user, void *in, size_t len) {
    switch (reason) {
    case LWS_CALLBACK_CLIENT_CONNECTION_ERROR:
        lwsl_err("CLIENT_CONNECTION_ERROR: %s\n", in ? (char *)in : "(null)");
        interrupted = 1;
        break;

    case LWS_CALLBACK_CLIENT_ESTABLISHED:
        lwsl_user("Connection established\n");
        send_website_status_request(wsi);  // Send website status request on connection
        lws_callback_on_writable(wsi); // Request writable callback
        break;

    case LWS_CALLBACK_CLIENT_WRITEABLE:
        if (time(NULL) - last_ping_time >= ping_interval) {
            send_ping(wsi);  // Send periodic ping
            last_ping_time = time(NULL);
            send_website_status_request(wsi);  // Periodically request website status
        }
        break;

    case LWS_CALLBACK_CLIENT_RECEIVE:
        // Accumulate incoming message chunks into the buffer
        if (message_length + len < sizeof(message_buffer) - 1) {
            memcpy(&message_buffer[message_length], in, len);
            message_length += len;
            message_buffer[message_length] = '\0';  // Null-terminate

            // Check if we have a complete JSON message
            if (is_json_complete(message_buffer)) {
                printf("Received complete JSON message: %s\n", message_buffer);
                handle_website_status_response(message_buffer); // Process JSON response
                message_length = 0;  // Reset the buffer after parsing
            }
        } else {
            printf("Warning: Message buffer overflow. Clearing buffer.\n");
            message_length = 0;  // Clear the buffer on overflow
        }
        break;

    case LWS_CALLBACK_CLIENT_CLOSED:
        lwsl_user("Connection closed\n");
        interrupted = 1;
        break;

    default:
        break;
    }

    return 0;
}

// Define supported protocols for the WebSocket
static const struct lws_protocols protocols[] = {
    { "lws-minimal-client", callback_minimal, 0, 0, 0, NULL, 0 },
    LWS_PROTOCOL_LIST_TERM
};

// Main function to set up and manage the WebSocket client
int main(int argc, const char **argv) {
    struct lws_context_creation_info info;
    struct lws_client_connect_info i;

    // Handle Ctrl+C interrupt for graceful shutdown
    signal(SIGINT, sigint_handler);
    memset(&info, 0, sizeof info);
    memset(&i, 0, sizeof(i));

    lwsl_user("Initializing Deriv WebSocket client...\n");

    info.options = LWS_SERVER_OPTION_DO_SSL_GLOBAL_INIT;
    info.port = CONTEXT_PORT_NO_LISTEN;
    info.protocols = protocols;
    info.fd_limit_per_thread = 1 + 1 + 1;

    context = lws_create_context(&info);
    if (!context) {
        lwsl_err("lws init failed\n");
        return 1;
    }

    i.context = context;
    i.port = port;
    i.address = server_address;
    i.path = path;
    i.host = i.address;
    i.origin = i.address;
    i.ssl_connection = ssl_connection;
    i.protocol = pro;
    i.local_protocol_name = "lws-minimal-client";

    if (!lws_client_connect_via_info(&i)) {
        lwsl_err("Failed to initiate connection\n");
        return 1;
    }

    // Run the WebSocket client event loop
    while (!interrupted)
        lws_service(context, 0);

    lws_context_destroy(context);
    lwsl_user("WebSocket client terminated.\n");

    return 0;
}

/*
 * Instructions:
 * 1. Install the required libraries if they are not already installed:
 *    - On Ubuntu:
 *        sudo apt-get install libwebsockets-dev libjansson-dev
 *    - On macOS:
 *        brew install libwebsockets jansson
 * 2. Compile the code using the following command:
 *      gcc -o connect connect.c -lwebsockets -ljansson -lssl -lcrypto -lm
 * 3. Run the compiled executable:
 *      ./connect
 * 4. Ensure you have internet connectivity as the WebSocket will attempt to connect to `ws.derivws.com`.
 * 5. Replace "app_id=1089" in the `path` variable with your actual app_id if required.
 */