Skip to content

Commit

Permalink
apollo c语言客户端
Browse files Browse the repository at this point in the history
  • Loading branch information
gvtcy committed Apr 10, 2020
0 parents commit e26d283
Show file tree
Hide file tree
Showing 10 changed files with 582 additions and 0 deletions.
5 changes: 5 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
/cygwin/
/libs/
/cmake-build-debug/
.idea
*.iml
7 changes: 7 additions & 0 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
cmake_minimum_required(VERSION 3.14)
project(apollo C)

set(CMAKE_C_STANDARD 99)

add_library(apollo SHARED apolloclient.c global.c)
target_link_libraries(apollo curl json-c)
25 changes: 25 additions & 0 deletions Makefile
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
CC=gcc
INCLIDE=.
CFLAGS= -Wall -std=c99
TARGET = libapollo.so
LIBPATH = ./libs/
OBJS=global.o apolloclient.o apollo.o
SRCS=global.c apolloclient.c apollo.c

all:$(OBJS)
$(CC) $(CFLAGS) -shared -fPIC -o $(TARGET) $(OBJS) -lcurl -ljson-c
mkdir -p $(LIBPATH)
mv $(TARGET) $(LIBPATH)
#$^代表所有依赖也就是上面的main.o mmath.o syso.o $@代表目标也就是上面main
$(OBJS):$(SRCS)
$(CC) $(CFLAGS) -fPIC -I$(INCLIDE) -c $^
install:
cp $(LIBPATH)$(TARGET) /lib64
mkdir -p /usr/include/apollo
cp ./*.h /usr/include/apollo
uninstall:
rm -rf /lib64/$(TARGET)
rm -rf /usr/include/apollo
clean:
rm -rf *.o
rm -f $(LIBPATH)*
104 changes: 104 additions & 0 deletions apollo.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,104 @@
//
// Created by GVT on 2020/4/2.
//
#include "string.h"
#include <apollo.h>
#include <curl/curl.h>
#include <json-c/json.h>



String getApolloConfig(ApolloConf apolloConf,String envName,String appId,String clusterName,String namespaceName){
CURL *curl = curl_easy_init();
if(curl) {
CURLcode res;
static char str[10000];
strcpy(str, "");
if(clusterName==NULL){
clusterName=DEFAULT_CLUSTER_NAME;
}
String urlDest=sprintfStr(LATESTREKEASE_URL, \
apolloConf.config_server_url,envName,appId,clusterName,namespaceName);
String tokenHeader=sprintfStr(TOKEN_PATTERN,apolloConf.token);
struct curl_slist *headers =setCommonHeader(&res,tokenHeader);
curl_easy_setopt(curl, CURLOPT_URL, urlDest);
curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, write_memory_callback);
curl_easy_setopt(curl, CURLOPT_WRITEDATA, str);
curl_easy_setopt(curl, CURLOPT_HTTPHEADER, headers);
res = curl_easy_perform(curl);
curl_easy_cleanup(curl);
free(tokenHeader);
free(urlDest);
return str;
}
return NULL;
}
void getApolloClusterEnv(ApolloConf apolloConf,String appId,envclusters* ec){
CURL *curl = curl_easy_init();
if(curl) {
CURLcode res;
static char str[10000];
strcpy(str, "");
String urlDest=sprintfStr(CLUSTERENV_URL, \
apolloConf.config_server_url,appId);
String tokenHeader=sprintfStr(TOKEN_PATTERN,apolloConf.token);
struct curl_slist *headers =setCommonHeader(&res,tokenHeader);
curl_easy_setopt(curl, CURLOPT_URL, urlDest);
curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, write_memory_callback);
curl_easy_setopt(curl, CURLOPT_WRITEDATA, str);
curl_easy_setopt(curl, CURLOPT_HTTPHEADER, headers);
res = curl_easy_perform(curl);
curl_easy_cleanup(curl);
free(tokenHeader);
free(urlDest);
json_object* jsonObject=json_tokener_parse(str);
size_t objectSize=json_object_array_length(jsonObject);
ec->len=objectSize;
envcluster* envc=(envcluster*)malloc(objectSize*sizeof(envcluster));
for(int v=0;v<objectSize;v++){
json_object* clusterObj=json_object_array_get_idx(jsonObject,v);
json_object* env;
json_object_object_get_ex(clusterObj,"env",&env);
json_object* clusters;
json_object_object_get_ex(clusterObj,"clusters",&clusters);
String clustersArray[json_object_array_length(clusters)];
for(int i=0;i<json_object_array_length(clusters);i++){
json_object* clusterObj=json_object_array_get_idx(clusters,i);
clustersArray[i]=json_object_to_json_string(clusterObj);
}
envcluster envclusterTmp={
env:json_object_to_json_string(env),
clusters:clustersArray
};
*(envc+v)=envclusterTmp;
}
ec->clusters=envc;
}
}
void getProperties(ApolloConf apolloConf,String envName,String appId,String clusterName,String namespaceName,Properties* properties){
String str=getApolloConfig(apolloConf,envName,appId,clusterName,namespaceName);
json_object* jsonObject=json_tokener_parse(str);
json_object* configurations;
json_object_object_get_ex(jsonObject,"configurations",&configurations);
int i=0;
size_t configurationsLength=json_object_object_length(configurations);
String* keys=newString(sizeof(String)*configurationsLength);
String* values=newString(sizeof(String)*configurationsLength);
properties->len=configurationsLength;
json_object_object_foreach(configurations,json_key,jsonValue){
keys[i]=json_key;
values[i]=json_object_get_string(jsonValue);
i++;
}
properties->keys=keys;
properties->values=values;
}
void getYamlOrJson(ApolloConf apolloConf,String envName,String appId,String clusterName,String namespaceName,String yamlStr){
Properties* properties;
getProperties(apolloConf,envName,appId,clusterName,namespaceName,properties);
for(int i=0;i<properties->len;i++){
if(strcmp(*(properties+i)->keys,"content")==0){
strcat(yamlStr,*(properties)->values);
}
}
}
107 changes: 107 additions & 0 deletions apollo.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,107 @@
//
// Created by jiaozi<[email protected]> on 2020/4/2.
//

#include "global.h"
#ifndef NGINX_APOLLO_H
#define NGINX_APOLLO_H

#endif //NGINX_APOLLO_H
#define TOKEN_PATTERN "Authorization:%s"

#define LATESTREKEASE_URL "http://%s/openapi/v1/envs/%s/apps/%s/clusters/%s/namespaces/%s/releases/latest"
#define CLUSTERENV_URL "http://%s/openapi/v1/apps/%s/envclusters"



typedef struct{
String config_server_url;
String token;
} ApolloConf;
/**
* 获取apollo配置
* properties输出结果是:
* {
"appId": "test-0620-01",
"clusterName": "test",
"namespaceName": "application",
"name": "2016-08-11",
"configurations": {
"timeout": "3000",
}
},只需要获取configurations所有key即可。
* yaml和json输出的结果是:
直接获取["configurations"]["content"]
* @param apolloConf Apollo配置服务的地址和token
* @param envName 环境名称
* @param appId 应用的appId
* @param clusterName 集群名
* @param namespaceName Namespace的名字
* @param ip 应用部署的机器ip
* @return 字符串结果,其他逻辑自行处理
*/
char* getApolloConfig(ApolloConf apolloConf,String envName,String appId,String clusterName,String namespaceName);
typedef struct{
String env;
String* clusters;
} envcluster;
typedef struct{
size_t len;
envcluster* clusters;
} envclusters;
/**
* 获取App的环境,集群信息
* [
{
"env":"FAT",
"clusters":[ //集群列表
"default",
"FAT381"
]
},
{
"env":"UAT",
"clusters":[
"default"
]
},
{
"env":"PRO",
"clusters":[
"default",
"SHAOY",
"SHAJQ"
]
}
]
* @param apolloConf Apollo配置服务的地址和token
* @param appId 应用id
* @param envclusters 集群环境信息,返回引用
* @return
*/
void getApolloClusterEnv(ApolloConf apolloConf,String appId,envclusters* ec);


/**
* 获取properties,可以获取所有类型 yaml和properties其实是在content这个key下面
* @param apolloConf
* @param envName
* @param appId
* @param clusterName
* @param namespaceName
* @return
*/
void getProperties(ApolloConf apolloConf,String envName,String appId,String clusterName,String namespaceName,Properties* properties);
/**
* 获取yaml
* @param apolloConf
* @param envName
* @param appId
* @param clusterName
* @param namespaceName
* @return
*/
void getYamlOrJson(ApolloConf apolloConf,String envName,String appId,String clusterName,String namespaceName,String yamlStr);



140 changes: 140 additions & 0 deletions apolloclient.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,140 @@
//
// Created by GVT on 2020/4/7.
//
#include "apolloclient.h"
#include "pthread.h"
String getNoCachePropertyString(apollo_env apolloEnv){
CURL *curl = curl_easy_init();
if(curl) {
CURLcode res;
String str=newString(10000);
memset(str, 0, 10000);
if(apolloEnv.clusterName==NULL){
apolloEnv.clusterName=DEFAULT_CLUSTER_NAME;
}
String urlDest=sprintfStr(APOLLO_CONFIG_NOCACHE_URL, \
apolloEnv.meta,apolloEnv.appId,apolloEnv.clusterName,apolloEnv.namespaceName);
struct curl_slist *headers =setCommonHeader(&res,NULL);
curl_easy_setopt(curl, CURLOPT_URL, urlDest);
curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, write_memory_callback);
curl_easy_setopt(curl, CURLOPT_WRITEDATA, str);
curl_easy_setopt(curl, CURLOPT_HTTPHEADER, headers);
res = curl_easy_perform(curl);
curl_easy_cleanup(curl);
free(urlDest);
return str;
}
}
void getNoCacheProperty(apollo_env apolloEnv,Properties* properties){
String properStr=getNoCachePropertyString(apolloEnv);
jsonStrToProperties(properStr,"configurations",properties);
}
CURLcode checkNotifications(apollo_env apolloEnv,notification notifications,long* response_code,String notificationReturn){
CURL *curl = curl_easy_init();
char* buf=malloc(200);
if(curl) {
CURLcode res;
if(apolloEnv.clusterName==NULL){
apolloEnv.clusterName=DEFAULT_CLUSTER_NAME;
}
String notification=newString(200);
memset(notification, 0, 200);
strcat(notification,"[");
strcat(notification,"{");
strcat(notification,"\"namespaceName\": \"");
strcat(notification,notifications.namespaceName);
strcat(notification,"\",");
strcat(notification,"\"notificationId\": \"");
strcat(notification,sprintfStr("%d",notifications.notificationId));
strcat(notification,"\"");
strcat(notification,"}");
strcat(notification,"]");
notification=curl_escape(notification,strlen(notification));
String urlDest=sprintfStr(APOLLO_CONFIG_NOTI_URL, \
apolloEnv.meta,apolloEnv.appId,apolloEnv.clusterName,notification);
struct curl_slist *headers =setCommonHeader(&res,NULL);
curl_easy_setopt(curl, CURLOPT_URL, urlDest);
curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, write_memory_callback);
curl_easy_setopt(curl, CURLOPT_WRITEDATA, notificationReturn);
curl_easy_setopt(curl, CURLOPT_HTTPHEADER, headers);
res = curl_easy_perform(curl);
if(res == CURLE_OK) {
curl_easy_getinfo(curl, CURLINFO_RESPONSE_CODE, response_code);
}
curl_easy_cleanup(curl);
free(urlDest);
return res;
}

}

typedef struct
{
void *arg[4]; /* 参数*/
}ThreadParam;
void *notificationRun(void *arg)
{
ThreadParam* param=(ThreadParam*)arg;
apollo_env apolloEnv=*(apollo_env*)param->arg[0];
notification notifications=*(notification*)param->arg[1];
int* flag=(int*)param->arg[2];
void (*callback)(Properties* old,Properties* new);
callback=param->arg[3];
submitNotifications(apolloEnv,notifications,flag,callback);
return NULL;
}

int submitNotificationsAsync(apollo_env apolloEnv,notification notifications,int* flag,void (*callback)(Properties* old,Properties* new)){
ThreadParam param={0};
param.arg[0]=&apolloEnv;
param.arg[1]=&notifications;
param.arg[2]=flag;
param.arg[3]=callback;
pthread_t tid;
int tret = pthread_create(&tid, NULL, notificationRun, (void *)&param);
return tret;
}

void submitNotifications(apollo_env apolloEnv,notification notifications,int* flag,void (*callback)(Properties* old,Properties* new)){
//第一次获取资源信息。
Properties oldProperties;
getNoCacheProperty(apolloEnv,&oldProperties);
callback(NULL,&oldProperties);
long responseCode;
String notiStr=newString(1000);
memset(notiStr, 0, 1000);
Properties newProperties;
CURLcode res=checkNotifications(apolloEnv,notifications,&responseCode,notiStr);
//根据动态flag决定是否需要继续long pooling
while(flag>0) {
if (res == CURLE_OK) {
//304直接使用当前数据直接调用当前方法继续递归
if (res == 304) {
res=checkNotifications(apolloEnv,notifications,&responseCode,notiStr);
continue;
} else {
//200不管是否都需要获取最新的配置项
if (responseCode == 200) {
//获取最新的配置。
getNoCacheProperty(apolloEnv,&newProperties);
json_object *jsonObject = json_tokener_parse(notiStr);
json_object *notifyObj = json_object_array_get_idx(jsonObject, 0);
json_object *notificationIdObject;
json_object_object_get_ex(notifyObj, "notificationId", &notificationIdObject);
int notificationId = json_object_get_int(notificationIdObject);
if(notifications.notificationId>NOTIFICATION_ID_PLACEHOLDER){
callback(&oldProperties, &newProperties);
}
notifications.notificationId = notificationId;
oldProperties=newProperties;
// newProperties.len=0;
// free(newProperties.keys);
// free(newProperties.values);
memset(notiStr, 0, 1000);
res=checkNotifications(apolloEnv,notifications,&responseCode,notiStr);
}
}

}
}
}
Loading

0 comments on commit e26d283

Please sign in to comment.