انتقل إلى المحتوى

إرسال واستقبال JSON

في هذا البرنامج التعليمي، نشرح كيف يمكنك إرسال واستقبال رسائل JSON.

TCP و WebSocket

عند العمل مع JSON، يمكنك استخدام إما اتصال TCP أو اتصال WebSocket.

إرسال JSON

إذا اخترت استخدام JSON في التكامل الخاص بك، سيتعين عليك إرسال سلاسل تحتوي على JSON صالح إلى خادم cTrader. يجب أن تحتوي كائنات JSON التي يتم تمريرها كهذه السلاسل على المفاتيح التالية.

المفتاح نوع بيانات القيمة التعريف
"clientMsgId" سلسلة المعرف الفريد للرسالة. يجب إنشاء هذا المعرف وتعيينه على جانب العميل.
"payloadType" integer العدد الصحيح الذي يمثل الرسالة. تم تضمين قائمة كاملة بأنواع الحمولة الصالحة في ProtoOAPayloadType.
"payload" كائن JSON كائن JSON متداخل يحتوي على المحتويات الفعلية للرسالة.

يمكن العثور على مثال لسلسلة صالحة (تمثل رسالة ProtoOAApplicationAuthReq) أدناه.

"{"clientMsgId": "cm_id_2", "payloadType": 2100, "payload": {"clientId": "34Rsd_T098asHkl","clientSecret": "validClientSecret"}}"

لإرسال سلاسل JSON صحيحة، ستحتاج إلى إنشاء آلية مخصصة للتسلسل في لغة البرمجة التي اخترتها.

في الأمثلة أدناه، نحدد عدة طرق للتعامل مع التسلسل. يمكنك (ويجب عليك) تنفيذ الخاص بك اعتمادًا على لغة البرمجة المفضلة لديك ونمط (أنماط) التصميم.

أدناه، نحدد فئتين أساسيتين ثم ننشئ تمثيلاً مخصصًا لرسالة ProtoOAApplicationAuthReq.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
public abstract class OpenAPIMessageBase
{
    public string ClientMsgId { get; set; }
    public abstract int PayloadType { get; }
}

public abstract class OpenAPIMessagePayloadBase { }

public class ApplicationAuthReq : OpenAPIMessageBase
{
    public ApplicationAuthReq() { }
    public ApplicationAuthReq(string clientId, string clientSecret)
    {
        this.Payload = new ApplicationAuthReqPayload(clientId, clientSecret);
        this.ClientMsgId = Guid.NewGuid().ToString();
    }

    public override int PayloadType => 2100;
    public ApplicationAuthReqPayload? Payload { get; set; }

}

public class ApplicationAuthReqPayload : OpenAPIMessagePayloadBase
{
    public ApplicationAuthReqPayload() { }
    public ApplicationAuthReqPayload(string clientId, string clientSecret)
    {
        this.ClientId = clientId;
        this.ClientSecret = clientSecret;
    }
    public string ClientId { get; set; } = string.Empty;
    public string ClientSecret { get; set; } = string.Empty;
}

نقوم بإنشاء فئة أساسية لجميع رسائل Open API ونحدد، لأغراض العرض التوضيحي، الفئة لـ ProtoOAApplicationAuthReq.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
import uuid
import json

class OpenAPIMessage:

def payloadType(self):
    pass

def payload(self):
    pass

def clientMsgId(self):
    pass

def asJsonString(self):
    pass


class ApplicationAuthReq(OpenAPIMessage):

def __init__(self, clientId, clientSecret, clientMsgId = str(uuid.uuid4())):
    self.clientId = clientId
    self.clientSecret = client_secret
    self.payloadType = 2100
    self.clientMsgId = clientMsgId
    self.payload = {"clientId": self.clientId, "clientSecret": self.clientSecret}



def asJsonString(self):
    return json.dumps({"clientMsgId": self.clientMsgId, "payloadType": self.payloadType, "payload": self.payload})

بعد تنفيذ المنطق المطلوب، يجب أن تكون قادرًا على إرسال رسائل جديدة إلى خادم cTrader عن طريق إنشاء نسخ جديدة من الفئات التي تمثل هذه الرسائل ثم تمريرها إلى عميل TCP أو WebSocket المفضل لديك.

استقبال JSON

لاستقبال ومعالجة رسائل JSON، يجب عليك تنفيذ طريقة لإلغاء تسلسل سلسلة JSON إلى تمثيل لرسالة Open API.

لتنفيذ هذه الطريقة، قد تجد أنه من المفيد تهيئة خريطة (أو قاموس) حيث يمكن أن تكون أنواع الحمولة مفاتيح مع أسماء الفئات التي تمثل الرسائل كقيم. لأغراض معالجة الاستثناءات، قد ترغب في التحقق مما إذا كان نوع الحمولة للرسالة التي تلقيتها هو مفتاح في هذه الخريطة أو القاموس. إذا كان هذا المفتاح موجودًا، يمكنك إلغاء تسلسل الرسالة باستخدام أي منطق مناسب.

بعد تنفيذ مثل هذه الطريقة، يمكنك استخدامها كرد اتصال يتم تشغيله في كل مرة تتلقى فيها رسالة جديدة.

لاحظ أنه في المثال أدناه TMessage هو نوع عام.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
public static class MessageReceivedCallbacks
{
    public static Dictionary<int, Type> messages = new Dictionary<int, Type>
    {
        {2100, typeof(ApplicationAuthReq) },

    };

    public static TMessage ReadMessage<TMessage>(string jsonString) where TMessage : OpenAPIMessageBase
    {
        JsonDocument doc = JsonDocument.Parse(jsonString);
        int payloadType = doc.RootElement.GetProperty("payloadType").GetInt32();

        if (!messages.TryGetValue(payloadType, out var type))
            throw new Exception("This payload type is not supported");

        var result = JsonSerializer.Deserialize(jsonString, type)  as TMessage;

        return result;
    }
}

التحويل إلى نوع فرعي

طريقة ReadMessage() لا تقوم فعليًا بإرجاع فئة رسالة محددة؛ ستحتاج إلى التعامل مع التحويل لأسفل بشكل منفصل عند تلقي رسالة.

نضيف الطريقة التالية إلى فئة ApplicationAuthReq الخاصة بنا.

1
2
3
@staticmethod
def fromJson(jsonDct):
    return ApplicationAuthReq(clientId=jsonDct['payload']['clientId'], clientSecret=jsonDct['payload']['clientSecret'], clientMsgId=jsonDct['clientMsgId'])

ثم نضيف رد اتصال readMessage ونسترجع حمولة من قاموس.

1
2
3
4
5
6
7
8
9
class MessageReceivedCallbacks:

messagesDict = {2100: ApplicationAuthReq}

@staticmethod
def readMessage(jsonString):
    json_dct = json.loads(jsonString)
    payloadType = jsonDct['payloadType']
    return MessageReceivedCallbacks.messagesDict[payloadType].fromJson(jsonDct)

التحويل إلى نوع فرعي

نظرًا لأن Python مكتوب بشكل بطة، فلا حاجة للتعامل مع التحويل لأسفل بشكل منفصل. يمكنك إلغاء تسلسل سلسلة JSON إلى النوع المطلوب عند استلامها.