summaryrefslogtreecommitdiff
path: root/public/gcsdk/gcjob.h
blob: b4045311707178d705d4b28b4dae2269f3a1602b (plain) (blame)
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
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
//========= Copyright Valve Corporation, All rights reserved. ============//
//
// Purpose: 
//
//=============================================================================

#ifndef GCJOB_H
#define GCJOB_H
#ifdef _WIN32
#pragma once
#endif

#include "gcwebapikey.h"

namespace GCSDK
{

//a free standing utility function that takes in a newly allocated job, and tells the job to start executing. An example of this would be pStore = StartNewJobDelayed( new CFooJob( Params ) );
template < typename T >
inline typename T* StartNewJobDelayed( T* pNewJob )
{
	if ( pNewJob )
		pNewJob->StartJobDelayed( NULL );
	return pNewJob;
}

//-----------------------------------------------------------------------------
// Purpose: Control access to web api accounts so that they can be rate limited/blocked/exempt, etc
//-----------------------------------------------------------------------------

enum EWebAPIAccountLevel
{
	eWebAPIAccountLevel_RateLimited = 0,		//default, rate limit
	eWebAPIAccountLevel_Blocked = 1,			//block all requests
	eWebAPIAccountLevel_Unlimited = 2,			//do not rate limit
	eWebAPIAccountLevel_Elevated = 3,			//like rate limiting, but at a higher threshold
};

//resets all accounts to the default permission
void WebAPIAccount_ResetAllPermissions();
//called to associate a permission level with an account
void WebAPIAccount_SetPermission( AccountID_t nID, EWebAPIAccountLevel eLevel );
//external calling interface in case we want to use this from a non-WebAPI job
bool WebAPIAccount_BTrackUserAndValidate( AccountID_t nID, uint32 unIP );

//-----------------------------------------------------------------------------
// Purpose: handles a network message job from the client
//-----------------------------------------------------------------------------
class CGCJob : public CJob
{
public:
	// Constructor: when overriding job name a static string pointer must be used
	CGCJob( CGCBase *pGC, const char *pchJobName = NULL ) : CJob( pGC->GetJobMgr(), pchJobName ), m_pGC( pGC ), m_cHeartbeatsBeforeTimeout( k_cJobHeartbeatsBeforeTimeoutDefault ) {}

	// all GC jobs must implement one of these
	virtual bool BYieldingRunGCJob( IMsgNetPacket *pNetPacket )	{ return false; }
	virtual bool BYieldingRunGCJob()							{ return false; }

	virtual EServerType GetServerType() { return k_EServerTypeGC; }

	bool BYldSendMessageAndGetReply( CSteamID &steamIDTarget, CGCMsgBase &msgOut, uint nTimeoutSec, CGCMsgBase *pMsgIn, MsgType_t eMsg );
	bool BYldSendMessageAndGetReply( CSteamID &steamIDTarget, CGCMsgBase &msgOut, uint nTimeoutSec, IMsgNetPacket **ppNetPacket );
	bool BYldSendMessageAndGetReply( CSteamID &steamIDTarget, CProtoBufMsgBase &msgOut, uint nTimeoutSec, CProtoBufMsgBase *pMsgIn, MsgType_t eMsg );
	bool BYldSendMessageAndGetReply( CSteamID &steamIDTarget, CProtoBufMsgBase &msgOut, uint nTimeoutSec, IMsgNetPacket **ppNetPacket );

	virtual uint32 CHeartbeatsBeforeTimeout() { return m_cHeartbeatsBeforeTimeout; }
	void SetJobTimeout( uint nTimeoutSec ) { m_cHeartbeatsBeforeTimeout = 1 + ( ( nTimeoutSec * k_nMillion - 1 ) / k_cMicroSecJobHeartbeat ); }

protected:
	CGCBase *m_pGC;

private:
	virtual bool BYieldingRunJobFromMsg( IMsgNetPacket *pNetPacket )
	{
		return BYieldingRunGCJob( pNetPacket );
	}

	virtual bool BYieldingRunJob( void *pvStartParam )
	{
		return BYieldingRunGCJob();
	}

	uint32 m_cHeartbeatsBeforeTimeout;
};


//This template class is designed to be derived from various job types and provides an adapter for the run from message hook, and handles
//converting it over to an appropriate protobuf message for the caller as well as validating that it parsed properly. It will bail on processing
//the message if the protobuf does not parse.
template < typename TGCJobClass, typename TGCType, typename TProtoMsgClass >
class TProtoMsgJob :
	public TGCJobClass
{
public:
	typedef CProtoBufMsg< TProtoMsgClass >	TProtoMsg;

	TProtoMsgJob( TGCType* pGC ) : TGCJobClass( pGC )		{}

	virtual bool BYieldingRunJobFromMsg( IMsgNetPacket *pNetPacket ) OVERRIDE
	{
		TProtoMsg msg( pNetPacket );
		if ( !msg.Body().IsInitialized() )
			return false;

		return BYieldingRunJobFromProtoMsg( msg );
	}

	virtual bool BYieldingRunJobFromProtoMsg( const TProtoMsg& ProtoMsg ) = 0;
};

//a partial specialization of the proto message job to make it easier to use with GCJob
template < typename TProtoMsgClass >
class CGCProtoJob : public TProtoMsgJob < CGCJob, CGCBase, TProtoMsgClass >
{
public:
	CGCProtoJob( CGCBase* pGC ) : TProtoMsgJob( pGC )	{}
	//clients need to implement BYieldingRunJobFromProtoMsg
};

//-----------------------------------------------------------------------------
// CGCWGJob - A job invoked from forwarded WG messages
//-----------------------------------------------------------------------------
class CGCWGJob : public CGCJob
{
public:
	CGCWGJob( CGCBase *pGCBase );
	~CGCWGJob();
	bool BYieldingRunGCJob(  IMsgNetPacket * pNetPacket ); // invokes BYieldingRunJobFromRequest
	virtual bool BYieldingRunJobFromRequest( KeyValues *pkvRequest, KeyValues *pkvResponse ) = 0;
	virtual bool BVerifyParams( const CGCMsg<MsgGCWGRequest_t> & msg, KeyValues *pkvRequest, const WebApiFunc_t * pWebApiFunc );
	void SetWebApiFunc( const WebApiFunc_t * pWebApiFunc ) { m_pWebApiFunc = pWebApiFunc; }

	void SetErrorMessage( KeyValues *pkvErr, const char *pchErrorMsg, int32 nResult );

protected:
	KeyValues *m_pkvResponse;
	CUtlBuffer m_bufRequest; // packed binary form of the request
	const WebApiFunc_t * m_pWebApiFunc;

	// requester auth info, like WGRequestContext
	CSteamID m_steamID;
};


//-----------------------------------------------------------------------------
// CGCJobVerifySession - A job that asks steam if a given user is still connected
//  and cleans up the session if the user is gone
//-----------------------------------------------------------------------------
class CGCJobVerifySession : public CGCJob
{
public:
	CGCJobVerifySession( CGCBase *pGC, const CSteamID &steamID ) : CGCJob( pGC ), m_steamID( steamID ) { }
	virtual bool BYieldingRunGCJob();

private:
	CSteamID m_steamID;
};



//-----------------------------------------------------------------------------
// CWebAPIJob - A job invoked from a forwarded WebAPI request
//-----------------------------------------------------------------------------
class CWebAPIJob : public CGCJob
{
public:
	CWebAPIJob( CGCBase *pGC, EWebAPIOutputFormat eDefaultOutputFormat = k_EWebAPIOutputFormat_JSON );
	~CWebAPIJob();

	// Called by jobmgr, and then invokes appropriate run function for specific API version requested
	bool BYieldingRunJobFromMsg( IMsgNetPacket * pNetPacket ); 

	// Implemented by each individual WebAPI job, should be declared using BEGIN_WEBAPI_JOB_VERSION_ADAPTERS and related macros.
	virtual bool BYieldingRunJobFromAPIRequest( const char *pchInterface, const char *pchMethod, uint32 unVersion, CHTTPRequest *pRequest, CHTTPResponse *pResponse, CWebAPIResponse *pWebAPIResponse  ) = 0;

protected:
	static void AddLocalizedString( CWebAPIValues *pOutDefn, const char *pchFieldName, const char *pchKeyName, ELanguage eLang, bool bReturnTokenIfNotFound = true );
	static void ThreadedEmitFormattedOutputWrapper( CWebAPIResponse *pResponse, EWebAPIOutputFormat eFormat, CUtlBuffer *poutputBuffer, size_t unMaxResultSize, bool *pbResult );

	CWebAPIKey m_webAPIKey;
	EWebAPIOutputFormat m_eDefaultOutputFormat; 
};


#define BEGIN_WEBAPI_JOB_VERSION_ADAPTERS( interface, method ) \
	bool BYieldingRunJobFromAPIRequest( const char *pchInterface, const char *pchMethod, uint32 unVersion, CHTTPRequest *pRequest, CHTTPResponse *pResponse, CWebAPIResponse *pWebAPIResponse  ) \
{ \
	if ( Q_strnicmp( pchInterface, interface, Q_strlen( interface ) ) != 0 ) \
{ \
	AssertMsg2( false, "WebAPIJob recieved request for unexpected interface (got %s, expected %s)!", pchInterface, interface ); \
	pResponse->SetStatusCode( k_EHTTPStatusCode500InternalServerError ); \
	return false; \
} \
	\
	if ( Q_stricmp( pchMethod, method ) != 0 ) \
{ \
	AssertMsg2( false, "WebAPIJob received request fo unexpected method (got %s, expected %s)!", pchMethod, method ); \
	pResponse->SetStatusCode( k_EHTTPStatusCode500InternalServerError ); \
	return false; \
} \
	\
	\
	bool bFoundVersion = false; \
	bool bResult = false; \
	switch( unVersion ) \
{ 

#define WEBAPI_JOB_VERSION_ADAPTER( version, funcname ) \
	case version: \
	bFoundVersion = true; \
	{ \
	VPROF_BUDGET( #funcname, VPROF_BUDGETGROUP_JOBS_COROUTINES ); \
	bResult = this->##funcname( pRequest, pWebAPIResponse ); \
	} \
	break; 

#define WEBAPI_JOB_VERSION_ADAPTER_EXTENDED_ARRAYS( version, funcname ) \
	case version: \
	bFoundVersion = true; \
	pWebAPIResponse->SetExtendedArrays( true ); \
	{ \
	VPROF_BUDGET( #funcname, VPROF_BUDGETGROUP_JOBS_COROUTINES ); \
	bResult = this->##funcname( pRequest, pWebAPIResponse ); \
	} \
	break; 

#define END_WEBAPI_JOB_VERSION_ADAPTERS() \
	default: \
	break; \
} \
	AssertMsg3( bFoundVersion, "WebAPIJob for %s/%s received unhandled version %d", pchInterface, pchMethod, unVersion ); \
	return bResult; \
}




} // namespace GCSDK


#endif // GCJOB_H