提交
This commit is contained in:
+190
@@ -0,0 +1,190 @@
|
||||
package com.aivfo.el.start.core.jackson;
|
||||
|
||||
import com.aivfo.el.starter.base.utils.Charsets;
|
||||
import com.fasterxml.jackson.core.JsonEncoding;
|
||||
import com.fasterxml.jackson.core.JsonGenerator;
|
||||
import com.fasterxml.jackson.core.JsonProcessingException;
|
||||
import com.fasterxml.jackson.core.PrettyPrinter;
|
||||
import com.fasterxml.jackson.core.util.DefaultIndenter;
|
||||
import com.fasterxml.jackson.core.util.DefaultPrettyPrinter;
|
||||
import com.fasterxml.jackson.databind.*;
|
||||
import com.fasterxml.jackson.databind.exc.InvalidDefinitionException;
|
||||
import com.fasterxml.jackson.databind.ser.FilterProvider;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
import org.springframework.http.HttpOutputMessage;
|
||||
import org.springframework.http.MediaType;
|
||||
import org.springframework.http.converter.AbstractGenericHttpMessageConverter;
|
||||
import org.springframework.http.converter.HttpMessageConversionException;
|
||||
import org.springframework.http.converter.HttpMessageNotWritableException;
|
||||
import org.springframework.http.converter.json.AbstractJackson2HttpMessageConverter;
|
||||
import org.springframework.http.converter.json.MappingJacksonValue;
|
||||
import org.springframework.util.TypeUtils;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.lang.reflect.Type;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
import java.util.concurrent.atomic.AtomicReference;
|
||||
|
||||
/**
|
||||
* @author: wangyl
|
||||
* @date: 2023/5/16
|
||||
* @description: 分读写的 json 消息 处理器
|
||||
*/
|
||||
public abstract class AbstractReadWriteJackson2HttpMessageConverter extends AbstractJackson2HttpMessageConverter {
|
||||
/**
|
||||
* DEFAULT_CHARSET
|
||||
*/
|
||||
private static final java.nio.charset.Charset DEFAULT_CHARSET = Charsets.UTF_8;
|
||||
|
||||
/**
|
||||
* Write object mapper
|
||||
*/
|
||||
private final ObjectMapper writeObjectMapper;
|
||||
/**
|
||||
* Sse pretty printer
|
||||
*/
|
||||
@Nullable
|
||||
private PrettyPrinter ssePrettyPrinter;
|
||||
|
||||
/**
|
||||
* Instantiates a new Abstract read write jackson 2 http message converter.
|
||||
*
|
||||
* @param readObjectMapper the read object mapper
|
||||
* @param writeObjectMapper the write object mapper
|
||||
* @param supportedMediaType the supported media type
|
||||
* @since 1.0.0
|
||||
*/
|
||||
protected AbstractReadWriteJackson2HttpMessageConverter(ObjectMapper readObjectMapper,
|
||||
ObjectMapper writeObjectMapper,
|
||||
MediaType supportedMediaType) {
|
||||
this(readObjectMapper, writeObjectMapper);
|
||||
this.setSupportedMediaTypes(Collections.singletonList(supportedMediaType));
|
||||
this.initSsePrettyPrinter();
|
||||
}
|
||||
|
||||
/**
|
||||
* Instantiates a new Abstract read write jackson 2 http message converter.
|
||||
*
|
||||
* @param readObjectMapper the read object mapper
|
||||
* @param writeObjectMapper the write object mapper
|
||||
* @since 1.0.0
|
||||
*/
|
||||
protected AbstractReadWriteJackson2HttpMessageConverter(ObjectMapper readObjectMapper, ObjectMapper writeObjectMapper) {
|
||||
super(readObjectMapper);
|
||||
this.writeObjectMapper = writeObjectMapper;
|
||||
this.initSsePrettyPrinter();
|
||||
}
|
||||
|
||||
/**
|
||||
* Init sse pretty printer
|
||||
*
|
||||
* @since 1.0.0
|
||||
*/
|
||||
private void initSsePrettyPrinter() {
|
||||
this.setDefaultCharset(DEFAULT_CHARSET);
|
||||
DefaultPrettyPrinter prettyPrinter = new DefaultPrettyPrinter();
|
||||
prettyPrinter.indentObjectsWith(new DefaultIndenter(" ", "\ndata:"));
|
||||
this.ssePrettyPrinter = prettyPrinter;
|
||||
}
|
||||
|
||||
/**
|
||||
* Instantiates a new Abstract read write jackson 2 http message converter.
|
||||
*
|
||||
* @param readObjectMapper the read object mapper
|
||||
* @param writeObjectMapper the write object mapper
|
||||
* @param supportedMediaTypes the supported media types
|
||||
* @since 1.0.0
|
||||
*/
|
||||
protected AbstractReadWriteJackson2HttpMessageConverter(ObjectMapper readObjectMapper,
|
||||
ObjectMapper writeObjectMapper,
|
||||
MediaType... supportedMediaTypes) {
|
||||
this(readObjectMapper, writeObjectMapper);
|
||||
this.setSupportedMediaTypes(Arrays.asList(supportedMediaTypes));
|
||||
}
|
||||
|
||||
/**
|
||||
* Can write boolean
|
||||
*
|
||||
* @param clazz clazz
|
||||
* @param mediaType media type
|
||||
* @return the boolean
|
||||
* @since 1.0.0
|
||||
*/
|
||||
@Override
|
||||
public boolean canWrite(@NotNull Class<?> clazz, @Nullable MediaType mediaType) {
|
||||
if (!this.canWrite(mediaType)) {
|
||||
return false;
|
||||
}
|
||||
AtomicReference<Throwable> causeRef = new AtomicReference<>();
|
||||
if (this.objectMapper.canSerialize(clazz, causeRef)) {
|
||||
return true;
|
||||
}
|
||||
this.logWarningIfNecessary(clazz, causeRef.get());
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* 最终的序列化逻辑
|
||||
*
|
||||
* @param object object
|
||||
* @param type type
|
||||
* @param outputMessage output message
|
||||
* @throws IOException io exception
|
||||
* @throws HttpMessageNotWritableException http message not writable exception
|
||||
* @see AbstractGenericHttpMessageConverter#write
|
||||
* @since 1.0.0
|
||||
*/
|
||||
@Override
|
||||
protected void writeInternal(@NotNull Object object, @Nullable Type type, @NotNull HttpOutputMessage outputMessage)
|
||||
throws IOException, HttpMessageNotWritableException {
|
||||
|
||||
MediaType contentType = outputMessage.getHeaders().getContentType();
|
||||
JsonEncoding encoding = this.getJsonEncoding(contentType);
|
||||
JsonGenerator generator = this.writeObjectMapper.getFactory().createGenerator(outputMessage.getBody(), encoding);
|
||||
try {
|
||||
this.writePrefix(generator, object);
|
||||
|
||||
Object value = object;
|
||||
Class<?> serializationView = null;
|
||||
FilterProvider filters = null;
|
||||
JavaType javaType = null;
|
||||
|
||||
if (object instanceof MappingJacksonValue) {
|
||||
MappingJacksonValue container = (MappingJacksonValue) object;
|
||||
value = container.getValue();
|
||||
serializationView = container.getSerializationView();
|
||||
filters = container.getFilters();
|
||||
}
|
||||
if (type != null && TypeUtils.isAssignable(type, value.getClass())) {
|
||||
javaType = this.getJavaType(type, null);
|
||||
}
|
||||
|
||||
ObjectWriter objectWriter = (serializationView != null
|
||||
? this.writeObjectMapper.writerWithView(serializationView)
|
||||
: this.writeObjectMapper.writer());
|
||||
if (filters != null) {
|
||||
objectWriter = objectWriter.with(filters);
|
||||
}
|
||||
if (javaType != null && javaType.isContainerType()) {
|
||||
objectWriter = objectWriter.forType(javaType);
|
||||
}
|
||||
SerializationConfig config = objectWriter.getConfig();
|
||||
if (contentType != null
|
||||
&& contentType.isCompatibleWith(MediaType.TEXT_EVENT_STREAM)
|
||||
&& config.isEnabled(SerializationFeature.INDENT_OUTPUT)) {
|
||||
objectWriter = objectWriter.with(this.ssePrettyPrinter);
|
||||
}
|
||||
objectWriter.writeValue(generator, value);
|
||||
|
||||
this.writeSuffix(generator, object);
|
||||
generator.flush();
|
||||
} catch (InvalidDefinitionException ex) {
|
||||
throw new HttpMessageConversionException("Type definition error: " + ex.getType(), ex);
|
||||
} catch (JsonProcessingException ex) {
|
||||
throw new HttpMessageNotWritableException("Could not write JSON: " + ex.getOriginalMessage(), ex);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
+140
@@ -0,0 +1,140 @@
|
||||
package com.aivfo.el.start.core.jackson;
|
||||
|
||||
import com.aivfo.el.starter.base.utils.StringPool;
|
||||
import com.aivfo.el.starter.base.utils.StringUtils;
|
||||
import com.fasterxml.jackson.core.JsonGenerator;
|
||||
import com.fasterxml.jackson.databind.*;
|
||||
import com.fasterxml.jackson.databind.ser.BeanPropertyWriter;
|
||||
import com.fasterxml.jackson.databind.ser.DefaultSerializerProvider;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.time.OffsetDateTime;
|
||||
import java.time.temporal.TemporalAccessor;
|
||||
import java.util.Collection;
|
||||
import java.util.Date;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* <p>Description: jackson 默认值为 null 时的处理,
|
||||
* 规则:
|
||||
* {@code
|
||||
* number: 0
|
||||
* string: null
|
||||
* date: null
|
||||
* boolean: false
|
||||
* array: []
|
||||
* Object: {}
|
||||
* }
|
||||
*/
|
||||
public class DefaultBeanSerializerModifier extends com.fasterxml.jackson.databind.ser.BeanSerializerModifier {
|
||||
/**
|
||||
* Change properties list
|
||||
*
|
||||
* @param config config
|
||||
* @param beanDesc bean desc
|
||||
* @param beanProperties bean properties
|
||||
* @return the list
|
||||
* @see DefaultSerializerProvider#_serializeNull(JsonGenerator)
|
||||
* @since 1.0.0
|
||||
*/
|
||||
@Override
|
||||
@SuppressWarnings("all")
|
||||
public List<BeanPropertyWriter> changeProperties(SerializationConfig config,
|
||||
BeanDescription beanDesc,
|
||||
@NotNull List<BeanPropertyWriter> beanProperties) {
|
||||
beanProperties.forEach(writer -> {
|
||||
// 如果已经有 null 序列化处理如注解: @JsonSerialize(nullsUsing = xxx) 跳过
|
||||
if (writer.hasNullSerializer()) {
|
||||
return;
|
||||
}
|
||||
JavaType type = writer.getType();
|
||||
Class<?> clazz = type.getRawClass();
|
||||
if (type.isTypeOrSubTypeOf(Number.class)) {
|
||||
// writer.assignNullSerializer(NullJsonSerializers.NUMBER_JSON_SERIALIZER);
|
||||
} else if (type.isTypeOrSubTypeOf(Boolean.class)) {
|
||||
writer.assignNullSerializer(NullJsonSerializers.BOOLEAN_JSON_SERIALIZER);
|
||||
} else if (type.isTypeOrSubTypeOf(Character.class)) {
|
||||
writer.assignNullSerializer(NullJsonSerializers.STRING_JSON_SERIALIZER);
|
||||
} else if (type.isTypeOrSubTypeOf(String.class)) {
|
||||
writer.assignNullSerializer(NullJsonSerializers.STRING_JSON_SERIALIZER);
|
||||
} else if (type.isArrayType() || clazz.isArray() || type.isTypeOrSubTypeOf(Collection.class)) {
|
||||
writer.assignNullSerializer(NullJsonSerializers.ARRAY_JSON_SERIALIZER);
|
||||
} else if (type.isTypeOrSubTypeOf(OffsetDateTime.class)) {
|
||||
writer.assignNullSerializer(NullJsonSerializers.STRING_JSON_SERIALIZER);
|
||||
} else if (type.isTypeOrSubTypeOf(Date.class) || type.isTypeOrSubTypeOf(TemporalAccessor.class)) {
|
||||
writer.assignNullSerializer(NullJsonSerializers.STRING_JSON_SERIALIZER);
|
||||
} else {
|
||||
writer.assignNullSerializer(NullJsonSerializers.OBJECT_JSON_SERIALIZER);
|
||||
}
|
||||
});
|
||||
return super.changeProperties(config, beanDesc, beanProperties);
|
||||
}
|
||||
|
||||
/**
|
||||
* The interface Null json serializers.
|
||||
*
|
||||
* @author dong4j
|
||||
* @version 1.2.3
|
||||
* @email "mailto:dongshijie@fkhwl.com"
|
||||
* @date 2019.12.24 01:46
|
||||
* @since 1.0.0
|
||||
*/
|
||||
@SuppressWarnings("checkstyle:InterfaceIsType")
|
||||
public interface NullJsonSerializers {
|
||||
|
||||
/**
|
||||
* The constant STRING_JSON_SERIALIZER.
|
||||
*/
|
||||
JsonSerializer<Object> STRING_JSON_SERIALIZER = new JsonSerializer<Object>() {
|
||||
@Override
|
||||
public void serialize(Object value, @NotNull JsonGenerator gen, SerializerProvider serializers) throws IOException {
|
||||
gen.writeString(StringPool.EMPTY);
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* The constant NUMBER_JSON_SERIALIZER.
|
||||
*/
|
||||
JsonSerializer<Object> NUMBER_JSON_SERIALIZER = new JsonSerializer<Object>() {
|
||||
@Override
|
||||
public void serialize(Object value, @NotNull JsonGenerator gen, SerializerProvider serializers) throws IOException {
|
||||
gen.writeNumber(StringUtils.INDEX_NOT_FOUND);
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* The constant BOOLEAN_JSON_SERIALIZER.
|
||||
*/
|
||||
JsonSerializer<Object> BOOLEAN_JSON_SERIALIZER = new JsonSerializer<Object>() {
|
||||
@Override
|
||||
public void serialize(Object value, @NotNull JsonGenerator gen, SerializerProvider serializers) throws IOException {
|
||||
gen.writeObject(Boolean.FALSE);
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* The constant ARRAY_JSON_SERIALIZER.
|
||||
*/
|
||||
JsonSerializer<Object> ARRAY_JSON_SERIALIZER = new JsonSerializer<Object>() {
|
||||
@Override
|
||||
public void serialize(Object value, @NotNull JsonGenerator gen, SerializerProvider serializers) throws IOException {
|
||||
gen.writeStartArray();
|
||||
gen.writeEndArray();
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* The constant OBJECT_JSON_SERIALIZER.
|
||||
*/
|
||||
JsonSerializer<Object> OBJECT_JSON_SERIALIZER = new JsonSerializer<Object>() {
|
||||
@Override
|
||||
public void serialize(Object value, @NotNull JsonGenerator gen, SerializerProvider serializers) throws IOException {
|
||||
gen.writeStartObject();
|
||||
gen.writeEndObject();
|
||||
}
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
+44
@@ -0,0 +1,44 @@
|
||||
package com.aivfo.el.start.core.jackson;
|
||||
|
||||
import com.aivfo.el.start.core.util.DateTimeUtils;
|
||||
import com.fasterxml.jackson.core.json.PackageVersion;
|
||||
import com.fasterxml.jackson.databind.module.SimpleModule;
|
||||
import com.fasterxml.jackson.datatype.jsr310.deser.LocalDateDeserializer;
|
||||
import com.fasterxml.jackson.datatype.jsr310.deser.LocalDateTimeDeserializer;
|
||||
import com.fasterxml.jackson.datatype.jsr310.deser.LocalTimeDeserializer;
|
||||
import com.fasterxml.jackson.datatype.jsr310.ser.LocalDateSerializer;
|
||||
import com.fasterxml.jackson.datatype.jsr310.ser.LocalDateTimeSerializer;
|
||||
import com.fasterxml.jackson.datatype.jsr310.ser.LocalTimeSerializer;
|
||||
|
||||
import java.time.LocalDate;
|
||||
import java.time.LocalDateTime;
|
||||
import java.time.LocalTime;
|
||||
|
||||
/**
|
||||
* @author: wangyl
|
||||
* @date: 2023/5/16
|
||||
* @description: java 8 时间默认序列化
|
||||
*/
|
||||
public class JavaTimeModule extends SimpleModule {
|
||||
|
||||
/**
|
||||
* serialVersionUID
|
||||
*/
|
||||
private static final long serialVersionUID = -8312156928465504942L;
|
||||
|
||||
/**
|
||||
* Java time module
|
||||
*
|
||||
* @since 1.0.0
|
||||
*/
|
||||
public JavaTimeModule() {
|
||||
super(PackageVersion.VERSION);
|
||||
this.addDeserializer(LocalDateTime.class, new LocalDateTimeDeserializer(DateTimeUtils.DATETIME_FORMAT));
|
||||
this.addDeserializer(LocalDate.class, new LocalDateDeserializer(DateTimeUtils.DATE_FORMAT));
|
||||
this.addDeserializer(LocalTime.class, new LocalTimeDeserializer(DateTimeUtils.TIME_FORMAT));
|
||||
this.addSerializer(LocalDateTime.class, new LocalDateTimeSerializer(DateTimeUtils.DATETIME_FORMAT));
|
||||
this.addSerializer(LocalDate.class, new LocalDateSerializer(DateTimeUtils.DATE_FORMAT));
|
||||
this.addSerializer(LocalTime.class, new LocalTimeSerializer(DateTimeUtils.TIME_FORMAT));
|
||||
}
|
||||
|
||||
}
|
||||
+107
@@ -0,0 +1,107 @@
|
||||
package com.aivfo.el.start.core.jackson;
|
||||
|
||||
import com.fasterxml.jackson.core.JsonGenerator;
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
import org.springframework.http.MediaType;
|
||||
import org.springframework.http.converter.json.Jackson2ObjectMapperBuilder;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
/**
|
||||
* 针对 api 服务对 android 和 ios 和 web 处理的 分读写的 jackson 处理 </p>
|
||||
* 1. app 端上报数据是 使用 readObjectMapper
|
||||
* 2. 返回给 app 端的数据使用 writeObjectMapper
|
||||
*/
|
||||
public class MappingApiJackson2HttpMessageConverter extends AbstractReadWriteJackson2HttpMessageConverter {
|
||||
|
||||
/**
|
||||
* Json prefix
|
||||
*/
|
||||
@Nullable
|
||||
private String jsonPrefix;
|
||||
|
||||
/**
|
||||
* Construct a new {@link MappingApiJackson2HttpMessageConverter} using default configuration
|
||||
* provided by {@link Jackson2ObjectMapperBuilder}.
|
||||
*
|
||||
* @since 1.0.0
|
||||
*/
|
||||
public MappingApiJackson2HttpMessageConverter() {
|
||||
this(Jackson2ObjectMapperBuilder.json().build());
|
||||
}
|
||||
|
||||
/**
|
||||
* Construct a new {@link MappingApiJackson2HttpMessageConverter} with a custom {@link ObjectMapper}.
|
||||
* You can use {@link Jackson2ObjectMapperBuilder} to build it easily.
|
||||
*
|
||||
* @param objectMapper ObjectMapper
|
||||
* @see Jackson2ObjectMapperBuilder#json() Jackson2ObjectMapperBuilder#json()Jackson2ObjectMapperBuilder#json()
|
||||
* @since 1.0.0
|
||||
*/
|
||||
public MappingApiJackson2HttpMessageConverter(ObjectMapper objectMapper) {
|
||||
super(objectMapper,
|
||||
initWriteObjectMapper(objectMapper),
|
||||
MediaType.APPLICATION_JSON,
|
||||
new MediaType("application", "*+json"));
|
||||
}
|
||||
|
||||
/**
|
||||
* 初始化负责序列化的 ObjectMapper, 设置 null 处理.
|
||||
* 如果需要扩展, 只需要重写 setSerializerFactory 即可.
|
||||
*
|
||||
* @param readObjectMapper read object mapper
|
||||
* @return the object mapper
|
||||
* @since 1.0.0
|
||||
*/
|
||||
private static @NotNull ObjectMapper initWriteObjectMapper(@NotNull ObjectMapper readObjectMapper) {
|
||||
// 拷贝 readObjectMapper
|
||||
ObjectMapper writeObjectMapper = readObjectMapper.copy();
|
||||
writeObjectMapper.setSerializerFactory(writeObjectMapper.getSerializerFactory()
|
||||
.withSerializerModifier(new DefaultBeanSerializerModifier()));
|
||||
return writeObjectMapper;
|
||||
}
|
||||
|
||||
/**
|
||||
* Specify a custom prefix to use for this view's JSON output.
|
||||
* Default is none.
|
||||
*
|
||||
* @param jsonPrefix jsonPrefix
|
||||
* @see #setPrefixJson #setPrefixJson#setPrefixJson#setPrefixJson#setPrefixJson#setPrefixJson
|
||||
* @since 1.0.0
|
||||
*/
|
||||
public void setJsonPrefix(@Nullable String jsonPrefix) {
|
||||
this.jsonPrefix = jsonPrefix;
|
||||
}
|
||||
|
||||
/**
|
||||
* Indicate whether the JSON output by this view should be prefixed with ")]}', ". Default is false.
|
||||
* <p>Prefixing the JSON string in this manner is used to help prevent JSON Hijacking.
|
||||
* The prefix renders the string syntactically invalid as a script so that it cannot be hijacked.
|
||||
* This prefix should be stripped before parsing the string as JSON.
|
||||
*
|
||||
* @param prefixJson prefixJson
|
||||
* @see #setJsonPrefix #setJsonPrefix#setJsonPrefix#setJsonPrefix#setJsonPrefix#setJsonPrefix
|
||||
* @since 1.0.0
|
||||
*/
|
||||
public void setPrefixJson(boolean prefixJson) {
|
||||
this.jsonPrefix = (prefixJson ? ")]}', " : null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Write prefix *
|
||||
*
|
||||
* @param generator generator
|
||||
* @param object object
|
||||
* @throws IOException io exception
|
||||
* @since 1.0.0
|
||||
*/
|
||||
@Override
|
||||
protected void writePrefix(@NotNull JsonGenerator generator, @NotNull Object object) throws IOException {
|
||||
if (this.jsonPrefix != null) {
|
||||
generator.writeRaw(this.jsonPrefix);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
+26
@@ -0,0 +1,26 @@
|
||||
package com.aivfo.dfs.autoconfigure;
|
||||
|
||||
import com.aivfo.dfs.client.core.Client;
|
||||
import com.aivfo.dfs.client.core.fastDFS.client.FastDFSClient;
|
||||
import com.aivfo.dfs.client.core.fastDFS.properties.FastDFSProperties;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
|
||||
import org.springframework.boot.context.properties.EnableConfigurationProperties;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.context.annotation.Primary;
|
||||
|
||||
|
||||
@Configuration
|
||||
@EnableConfigurationProperties(DfsAutoProperties.class)
|
||||
@ConditionalOnProperty(prefix = DfsAutoProperties.PREFIX, name = DfsAutoProperties.ENABLE, matchIfMissing = true)
|
||||
public class DfsAutoConfiguration {
|
||||
|
||||
@Bean
|
||||
@ConditionalOnProperty(prefix = DfsAutoProperties.FASTDFS_PREFIX, name = DfsAutoProperties.ENABLE, matchIfMissing = true)
|
||||
@Primary
|
||||
public Client fastDFSClient(DfsAutoProperties mqttProperties) {
|
||||
final FastDFSProperties fastDFS = mqttProperties.getFastdfs();
|
||||
return new FastDFSClient(fastDFS);
|
||||
}
|
||||
|
||||
}
|
||||
+41
@@ -0,0 +1,41 @@
|
||||
package com.aivfo.dfs.autoconfigure;
|
||||
|
||||
import com.aivfo.dfs.client.core.fastDFS.properties.FastDFSProperties;
|
||||
import lombok.Data;
|
||||
import org.springframework.boot.context.properties.ConfigurationProperties;
|
||||
|
||||
import javax.annotation.PostConstruct;
|
||||
|
||||
|
||||
/**
|
||||
* @author: wangyl
|
||||
* @date: 2023/4/19
|
||||
* @description:
|
||||
*/
|
||||
@ConfigurationProperties(prefix = DfsAutoProperties.PREFIX)
|
||||
@Data
|
||||
public class DfsAutoProperties {
|
||||
/**
|
||||
* PREFIX
|
||||
*/
|
||||
static final String PREFIX = "aivfo.dfs";
|
||||
|
||||
/**
|
||||
* FASTDFS_PREFIX
|
||||
*/
|
||||
static final String FASTDFS_PREFIX = "aivfo.dfs.fastDFS";
|
||||
/**
|
||||
* 开启的常量
|
||||
*/
|
||||
static final String ENABLE = "enable";
|
||||
/**
|
||||
* 默认开启
|
||||
*/
|
||||
private boolean enable = true;
|
||||
|
||||
/**
|
||||
* Clients
|
||||
*/
|
||||
private FastDFSProperties fastdfs;
|
||||
|
||||
}
|
||||
+2
@@ -0,0 +1,2 @@
|
||||
org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
|
||||
com.aivfo.dfs.autoconfigure.DfsAutoConfiguration
|
||||
+99
@@ -0,0 +1,99 @@
|
||||
package com.aivfo.dfs.client.core;
|
||||
|
||||
import com.aivfo.dfs.client.core.callback.DownloadCallBack;
|
||||
import com.csource.common.MyException;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* @author: wangyl
|
||||
* @date: 2023/4/27
|
||||
* @description: 客户端接口
|
||||
*/
|
||||
public interface Client {
|
||||
|
||||
/**
|
||||
* 通过文件路径上传文件
|
||||
*
|
||||
* @param fileFullName 文件全路径
|
||||
* @return java.lang.String 文件结果路径
|
||||
* @Date 2023/4/27
|
||||
* @Author wangyl
|
||||
*/
|
||||
String uploadFile(String fileFullName) throws Exception;
|
||||
|
||||
/**
|
||||
* 通过文件路径上传文件 可配置文件元数据以及上传组信息
|
||||
*
|
||||
* @param fileFullName 文件全路径
|
||||
* @param fileMetaList 文件元数据
|
||||
* @return java.lang.String 文件结果路径
|
||||
* @Date 2023/4/27
|
||||
* @Author wangyl
|
||||
*/
|
||||
String uploadFile(String fileFullName, Map<String, String> fileMetaList) throws Exception;
|
||||
|
||||
/**
|
||||
* 二进制流上传文件
|
||||
*
|
||||
* @param fileData 文件内容
|
||||
* @param fileName 文件名称
|
||||
* @return java.lang.String
|
||||
* @Date 2023/4/28
|
||||
* @Author wangyl
|
||||
*/
|
||||
String uploadFile(byte[] fileData, String fileName) throws Exception;
|
||||
|
||||
/**
|
||||
* 二进制流上传文件,附加文件属性
|
||||
*
|
||||
* @param fileData
|
||||
* @param fileName
|
||||
* @param fileMetaList
|
||||
* @return java.lang.String
|
||||
* @Date 2023/4/28
|
||||
* @Author wangyl
|
||||
*/
|
||||
String uploadFile(byte[] fileData, String fileName, Map<String, String> fileMetaList) throws Exception;
|
||||
|
||||
/**
|
||||
* 下载指定的远程文件
|
||||
*
|
||||
* @param remoteFile 远程文件路径
|
||||
* @return void
|
||||
* @Date 2023/5/10
|
||||
* @Author wangyl
|
||||
*/
|
||||
void downloadFile(String remoteFile, DownloadCallBack downloadCallBack) throws Exception;
|
||||
|
||||
/**
|
||||
* 下载文件流
|
||||
*
|
||||
* @param remoteFile 远程文件路径
|
||||
* @return void
|
||||
* @Date 2023/5/10
|
||||
* @Author wangyl
|
||||
*/
|
||||
byte[] downloadFile(String remoteFile) throws Exception;
|
||||
|
||||
/**
|
||||
* 获取文件真实磁盘路径
|
||||
*
|
||||
* @param uploadFileResultPath 上传文件的返回路径
|
||||
* @return java.lang.String
|
||||
* @Date 2023/5/5
|
||||
* @Author wangyl
|
||||
*/
|
||||
String getFileReallyPath(String uploadFileResultPath) throws Exception;
|
||||
|
||||
/**
|
||||
* 获取远程文件元数据
|
||||
*
|
||||
* @param remoteFile 远程文件
|
||||
* @return java.util.Map<java.lang.Object, java.lang.Object>
|
||||
* @Date 2023/5/10
|
||||
* @Author wangyl
|
||||
*/
|
||||
Map<String, String> getFileMeta(String remoteFile) throws Exception;
|
||||
}
|
||||
+36
@@ -0,0 +1,36 @@
|
||||
package com.aivfo.dfs.client.core.exception;
|
||||
|
||||
import com.aivfo.el.starter.base.exception.BasicException;
|
||||
|
||||
/**
|
||||
* @author: wangyl
|
||||
* @date: 2023/4/14
|
||||
* @description: Dfs异常信息
|
||||
*/
|
||||
public class DfsFailedException extends BasicException {
|
||||
|
||||
/**
|
||||
* DEFAULT_MESSAGE
|
||||
*/
|
||||
private static final String DEFAULT_MESSAGE = "服务内部错误: ";
|
||||
private static final long serialVersionUID = -4288134722183807545L;
|
||||
|
||||
/**
|
||||
* Basic exception
|
||||
*
|
||||
* @since 1.7.0
|
||||
*/
|
||||
public DfsFailedException() {
|
||||
super();
|
||||
}
|
||||
|
||||
/**
|
||||
* Base exception
|
||||
*
|
||||
* @param describe describe
|
||||
* @since 1.7.0
|
||||
*/
|
||||
public DfsFailedException(String describe) {
|
||||
super(DEFAULT_MESSAGE + describe);
|
||||
}
|
||||
}
|
||||
+235
@@ -0,0 +1,235 @@
|
||||
package com.aivfo.dfs.client.core.fastDFS.client;
|
||||
|
||||
import com.aivfo.dfs.client.core.Client;
|
||||
import com.aivfo.dfs.client.core.callback.DownloadCallBack;
|
||||
import com.aivfo.dfs.client.core.exception.DfsFailedException;
|
||||
import com.aivfo.dfs.client.core.fastDFS.callback.FileDownLoadCallBack;
|
||||
import com.aivfo.dfs.client.core.fastDFS.common.FastDFSUtils;
|
||||
import com.aivfo.dfs.client.core.fastDFS.constant.FastDFSCmd;
|
||||
import com.aivfo.dfs.client.core.fastDFS.constant.FastDFSConstant;
|
||||
import com.aivfo.dfs.client.core.fastDFS.properties.FastDFSProperties;
|
||||
import com.aivfo.el.start.core.util.CollectionUtils;
|
||||
import com.aivfo.el.start.core.util.FileUtils;
|
||||
import com.aivfo.el.starter.base.utils.StringPool;
|
||||
import com.csource.common.NameValuePair;
|
||||
import com.csource.fastdfs.*;
|
||||
import com.csource.fastdfs.pool.Connection;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.FileInputStream;
|
||||
import java.io.IOException;
|
||||
import java.util.*;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
/**
|
||||
* @author: wangyl
|
||||
* @date: 2023/4/28
|
||||
* @description: fastDFS客户端
|
||||
*/
|
||||
@Slf4j
|
||||
public class FastDFSClient implements Client {
|
||||
|
||||
FastDFSProperties fastDFSProperties;
|
||||
|
||||
/**
|
||||
* @author: wangyl
|
||||
* @date: 2023/5/4
|
||||
* @description: 初始化
|
||||
*/
|
||||
public FastDFSClient(FastDFSProperties fastDFSProperties) {
|
||||
this.fastDFSProperties = fastDFSProperties;
|
||||
Properties properties = this.fastDFSProperties.ConversionToProperties();
|
||||
try {
|
||||
ClientGlobal.initByProperties(properties);
|
||||
} catch (Exception e) {
|
||||
log.error("fastDFS初始化失败", e);
|
||||
System.exit(-1);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 初始化相关对象
|
||||
*
|
||||
* @param
|
||||
* @return org.csource.fastdfs.StorageClient
|
||||
* @Date 2023/4/28
|
||||
* @Author wangyl
|
||||
* @see StorageClient#releaseConnection(Connection, boolean)
|
||||
* 对象都是非线程安全的 所以每次调用的时候都需要初始化 storageServer 这个对象源码在每次操作后都会被设置为null
|
||||
*/
|
||||
private StorageClient getStorageClient() throws IOException {
|
||||
TrackerClient tracker = new TrackerClient();
|
||||
TrackerServer trackerServer = tracker.getTrackerServer();
|
||||
StorageServer storageServer = null;
|
||||
StorageClient storageClient = new StorageClient(trackerServer, storageServer);
|
||||
return storageClient;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String uploadFile(String fileFullName) throws Exception {
|
||||
return this.uploadFileByName(fileFullName, new HashMap<>());
|
||||
}
|
||||
|
||||
@Override
|
||||
public String uploadFile(String fileFullName, Map<String, String> fileMetaMap) throws Exception {
|
||||
return this.uploadFileByName(fileFullName, fileMetaMap);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String uploadFile(byte[] fileData, String fileName) throws Exception {
|
||||
return this.uploadFileByByte(fileData, fileName, new HashMap<>());
|
||||
}
|
||||
|
||||
@Override
|
||||
public String uploadFile(byte[] fileData, String fileName, Map<String, String> fileMetaMap) throws Exception {
|
||||
return this.uploadFileByByte(fileData, fileName, fileMetaMap);
|
||||
}
|
||||
|
||||
/**
|
||||
* 下载指定的远程文件
|
||||
*
|
||||
* @param remoteFile
|
||||
* @param downloadCallBack
|
||||
* @return void
|
||||
* @Date 2023/5/10
|
||||
* @Author wangyl
|
||||
*/
|
||||
@Override
|
||||
public void downloadFile(String remoteFile, DownloadCallBack downloadCallBack) throws Exception {
|
||||
this.downloadFileByCallBack(remoteFile, downloadCallBack);
|
||||
}
|
||||
|
||||
/**
|
||||
* 下载文件流
|
||||
*
|
||||
* @param remoteFile 远程文件路径
|
||||
* @return void
|
||||
* @Date 2023/5/10
|
||||
* @Author wangyl
|
||||
*/
|
||||
@Override
|
||||
public byte[] downloadFile(String remoteFile) throws Exception {
|
||||
return this.downloadFileByByte(remoteFile);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取文件真实磁盘路径
|
||||
* 解析原理:
|
||||
*
|
||||
* @param uploadFileResultPath 上传文件的返回路径 例如:group1/M00/00/00/rBfCtGRSpMOAMnasABPRK3dgG_Q507.jpg
|
||||
* @return java.lang.String
|
||||
* @Date 2023/5/5
|
||||
* @Author wangyl
|
||||
*/
|
||||
@Override
|
||||
public String getFileReallyPath(String uploadFileResultPath) {
|
||||
FastDFSUtils.FastDFSPathInfo fastDFSPathInfo = FastDFSUtils.spiltFileResultPath(uploadFileResultPath);
|
||||
Map<String, List<String>> storagePath = fastDFSProperties.getStoragePath();
|
||||
List<String> realPathPrefixList = storagePath.get(fastDFSPathInfo.getGroupName());
|
||||
Integer storagePathIndex = Integer.valueOf(fastDFSPathInfo.getStoragePath().substring(1));
|
||||
if (CollectionUtils.isEmpty(realPathPrefixList) || realPathPrefixList.size() < storagePathIndex) {
|
||||
throw new DfsFailedException("组【" + fastDFSPathInfo.getGroupName() + "】没有配置storagePath参数,或者配置storagePath不正确 请检查配置");
|
||||
}
|
||||
|
||||
String realPathPrefix = realPathPrefixList.get(storagePathIndex);
|
||||
String realPath = realPathPrefix + StringPool.SLASH + FastDFSConstant.STORAGE_PATH_DATA + StringPool.SLASH + fastDFSPathInfo.getDirFirst() + StringPool.SLASH + fastDFSPathInfo.getDirSecond() + StringPool.SLASH + fastDFSPathInfo.getFileName();
|
||||
return realPath;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取远程文件元数据
|
||||
*
|
||||
* @param remoteFile 远程文件
|
||||
* @return java.util.Map<java.lang.Object, java.lang.Object>
|
||||
* @Date 2023/5/10
|
||||
* @Author wangyl
|
||||
*/
|
||||
@Override
|
||||
public Map<String, String> getFileMeta(String remoteFile) throws Exception {
|
||||
StorageClient storageClient = this.getStorageClient();
|
||||
FastDFSUtils.FastDFSPathInfo fastDFSPathInfo = FastDFSUtils.spiltFileResultPath(remoteFile);
|
||||
NameValuePair[] metadata = storageClient.get_metadata(fastDFSPathInfo.getGroupName(), fastDFSPathInfo.toFileId());
|
||||
Map<String, String> collect = Arrays.stream(metadata).collect(Collectors.toMap(NameValuePair::getName, NameValuePair::getValue));
|
||||
return collect;
|
||||
}
|
||||
|
||||
/**
|
||||
* 通过完整的文件流上传
|
||||
*
|
||||
* @param fileData 文件数据
|
||||
* @param fileName 文件名称
|
||||
* @param fileMetaMap 文件元数据
|
||||
* @return java.lang.String
|
||||
* @Date 2023/5/4
|
||||
* @Author wangyl
|
||||
*/
|
||||
private String uploadFileByByte(byte[] fileData, String fileName, Map<String, String> fileMetaMap) throws Exception {
|
||||
StorageClient storageClient = getStorageClient();
|
||||
FileUtils.FileNameInfo fileNameInfo = FileUtils.splitFileExt(fileName);
|
||||
int fileSize = fileData.length;
|
||||
List<NameValuePair> nameValuePairs = FastDFSUtils.defaultNameValuePair(fileNameInfo);
|
||||
nameValuePairs.addAll(FastDFSUtils.mapToNameValuePair(fileMetaMap));
|
||||
String[] uploadResult = storageClient.do_upload_file(FastDFSCmd.STORAGE_PROTO_CMD_UPLOAD_FILE, null, null, fileNameInfo.getMainName(),
|
||||
fileNameInfo.getExtName(), fileSize, new StorageClient.UploadBuff(fileData, 0, fileSize), nameValuePairs.toArray(new NameValuePair[0]));
|
||||
return FastDFSUtils.uploadFileResultPath(uploadResult);
|
||||
}
|
||||
|
||||
/**
|
||||
* 按照本地文件上传
|
||||
*
|
||||
* @param fileFullName 文件全路径
|
||||
* @param fileMetaMap 文件元数据
|
||||
* @return java.lang.String
|
||||
* @Date 2023/5/4
|
||||
* @Author wangyl
|
||||
*/
|
||||
private String uploadFileByName(String fileFullName, Map<String, String> fileMetaMap) throws Exception {
|
||||
File file = new File(fileFullName);
|
||||
FileUtils.FileNameInfo fileNameInfo = FileUtils.splitFileExt(fileFullName);
|
||||
List<NameValuePair> nameValuePairs = FastDFSUtils.defaultNameValuePair(fileNameInfo);
|
||||
nameValuePairs.addAll(FastDFSUtils.mapToNameValuePair(fileMetaMap));
|
||||
FileInputStream fis = new FileInputStream(file);
|
||||
StorageClient storageClient = getStorageClient();
|
||||
String[] uploadResult = storageClient.do_upload_file(FastDFSCmd.STORAGE_PROTO_CMD_UPLOAD_FILE, null, null, fileNameInfo.getMainName(),
|
||||
fileNameInfo.getExtName(), file.length(), new UploadStream(fis, file.length()), nameValuePairs.toArray(new NameValuePair[0]));
|
||||
return FastDFSUtils.uploadFileResultPath(uploadResult);
|
||||
}
|
||||
|
||||
/**
|
||||
* 文件下载 结果发送回调函数
|
||||
*
|
||||
* @param uploadFileResultPath
|
||||
* @param downloadCallback
|
||||
* @return void
|
||||
* @Date 2023/5/10
|
||||
* @Author wangyl
|
||||
*/
|
||||
private void downloadFileByCallBack(String uploadFileResultPath, DownloadCallBack downloadCallback) throws Exception {
|
||||
StorageClient storageClient = this.getStorageClient();
|
||||
FastDFSUtils.FastDFSPathInfo fastDFSPathInfo = FastDFSUtils.spiltFileResultPath(uploadFileResultPath);
|
||||
FileDownLoadCallBack fileDownLoadCallBack = new FileDownLoadCallBack(downloadCallback);
|
||||
int result = storageClient.download_file(fastDFSPathInfo.getGroupName(), fastDFSPathInfo.toFileId(), 0L, 0L, fileDownLoadCallBack);
|
||||
if (result != 0) {
|
||||
throw new DfsFailedException();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 文件下载 返回字节流
|
||||
*
|
||||
* @param uploadFileResultPath
|
||||
* @return byte[]
|
||||
* @Date 2023/5/10
|
||||
* @Author wangyl
|
||||
*/
|
||||
private byte[] downloadFileByByte(String uploadFileResultPath) throws Exception {
|
||||
StorageClient storageClient = this.getStorageClient();
|
||||
FastDFSUtils.FastDFSPathInfo fastDFSPathInfo = FastDFSUtils.spiltFileResultPath(uploadFileResultPath);
|
||||
byte[] data = storageClient.download_file(fastDFSPathInfo.getGroupName(), fastDFSPathInfo.toFileId(), 0L, 0L);
|
||||
if (Objects.isNull(data)) {
|
||||
throw new DfsFailedException();
|
||||
}
|
||||
return data;
|
||||
}
|
||||
}
|
||||
+137
@@ -0,0 +1,137 @@
|
||||
package com.aivfo.dfs.client.core.fastDFS.common;
|
||||
|
||||
import com.aivfo.dfs.client.core.exception.DfsFailedException;
|
||||
import com.aivfo.dfs.client.core.fastDFS.constant.FastDFSConstant;
|
||||
import com.aivfo.el.start.core.util.FileUtils;
|
||||
import com.aivfo.el.starter.base.utils.StringPool;
|
||||
import com.csource.common.NameValuePair;
|
||||
import lombok.Data;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
/**
|
||||
* @author: wangyl
|
||||
* @date: 2023/5/4
|
||||
* @description: DFS文件工具
|
||||
*/
|
||||
public class FastDFSUtils {
|
||||
final static Integer RESULT_SIZE = 2;
|
||||
|
||||
/**
|
||||
* 获取文件上传结果
|
||||
*
|
||||
* @param uploadFileResult
|
||||
* @return java.lang.String
|
||||
* @Date 2023/5/4
|
||||
* @Author wangyl
|
||||
*/
|
||||
public static String uploadFileResultPath(String[] uploadFileResult) {
|
||||
if (Objects.isNull(uploadFileResult) || uploadFileResult.length < RESULT_SIZE) {
|
||||
throw new DfsFailedException("上传结果异常");
|
||||
}
|
||||
return uploadFileResult[0] + "/" + uploadFileResult[1];
|
||||
}
|
||||
|
||||
/**
|
||||
* map 转fastDFS的文件元数据
|
||||
*
|
||||
* @param fileMetaMap
|
||||
* @return com.csource.common.NameValuePair[]
|
||||
* @Date 2023/5/4
|
||||
* @Author wangyl
|
||||
*/
|
||||
public static List<NameValuePair> mapToNameValuePair(Map<String, String> fileMetaMap) {
|
||||
List<NameValuePair> nameValuePairs = fileMetaMap.entrySet().stream().map((key) -> {
|
||||
NameValuePair nameValuePair = new NameValuePair(key.getKey(), key.getValue());
|
||||
return nameValuePair;
|
||||
}).collect(Collectors.toList());
|
||||
return nameValuePairs;
|
||||
}
|
||||
|
||||
/**
|
||||
* 文件默认原属性生成
|
||||
*
|
||||
* @param fileNameInfo
|
||||
* @return java.util.List<com.csource.common.NameValuePair>
|
||||
* @Date 2023/5/10
|
||||
* @Author wangyl
|
||||
*/
|
||||
public static List<NameValuePair> defaultNameValuePair(FileUtils.FileNameInfo fileNameInfo) {
|
||||
final List<NameValuePair> defaultNameValuePairList = new ArrayList<>();
|
||||
NameValuePair mainName = new NameValuePair(FastDFSConstant.FILE_NAME, fileNameInfo.getMainName());
|
||||
NameValuePair extName = new NameValuePair(FastDFSConstant.FILE_EXT_NAME, fileNameInfo.getExtName());
|
||||
defaultNameValuePairList.add(mainName);
|
||||
defaultNameValuePairList.add(extName);
|
||||
return defaultNameValuePairList;
|
||||
}
|
||||
|
||||
/**
|
||||
* 上传结果切割
|
||||
*
|
||||
* @param uploadFileResultPath
|
||||
* @return com.aivfo.dfs.client.core.fastDFS.common.FastDFSUtils.FastDFSPathInfo
|
||||
* @Date 2023/5/10
|
||||
* @Author wangyl
|
||||
*/
|
||||
public static FastDFSPathInfo spiltFileResultPath(String uploadFileResultPath) {
|
||||
if (uploadFileResultPath.startsWith(StringPool.SLASH)) {
|
||||
uploadFileResultPath = uploadFileResultPath.substring(1);
|
||||
}
|
||||
String[] split = uploadFileResultPath.split(StringPool.SLASH);
|
||||
if (split.length < FastDFSConstant.UPLOAD_FILE_RESULT_SPILT_PATH || !split[1].startsWith(FastDFSConstant.STORAGE_PATH_START)) {
|
||||
throw new DfsFailedException("uploadFileResultPath 输入错误。请输入例如:group1/M00/00/00/rBfCtGRSpMOAMnasABPRK3dgG_Q507.jpg 的路径");
|
||||
}
|
||||
FastDFSPathInfo fastDFSPathInfo = new FastDFSPathInfo();
|
||||
fastDFSPathInfo.setGroupName(split[0]);
|
||||
fastDFSPathInfo.setStoragePath(split[1]);
|
||||
fastDFSPathInfo.setDirFirst(split[2]);
|
||||
fastDFSPathInfo.setDirSecond(split[3]);
|
||||
fastDFSPathInfo.setFileName(split[4]);
|
||||
return fastDFSPathInfo;
|
||||
}
|
||||
|
||||
/**
|
||||
* @author: wangyl
|
||||
* @date: 2023/5/10
|
||||
* @description: fastDFS路径信息
|
||||
*/
|
||||
@Data
|
||||
public static class FastDFSPathInfo {
|
||||
/**
|
||||
* 分组名字
|
||||
*/
|
||||
String groupName;
|
||||
/**
|
||||
* 存储路径信息
|
||||
*/
|
||||
String storagePath;
|
||||
/**
|
||||
* 第一个文件夹
|
||||
*/
|
||||
String dirFirst;
|
||||
/**
|
||||
* 第二个文件夹
|
||||
*/
|
||||
String dirSecond;
|
||||
/**
|
||||
* 文件名字
|
||||
*/
|
||||
String fileName;
|
||||
|
||||
/**
|
||||
* 返回文件id
|
||||
*
|
||||
* @param
|
||||
* @return java.lang.String
|
||||
* @Date 2023/5/10
|
||||
* @Author wangyl
|
||||
*/
|
||||
public String toFileId() {
|
||||
return storagePath + StringPool.SLASH + dirFirst + StringPool.SLASH + dirSecond + StringPool.SLASH + fileName;
|
||||
}
|
||||
}
|
||||
}
|
||||
+13
@@ -0,0 +1,13 @@
|
||||
package com.aivfo.dfs.client.core.fastDFS.constant;
|
||||
|
||||
/**
|
||||
* @author: wangyl
|
||||
* @date: 2023/5/4
|
||||
* @description: 客户端和服务端交互的命令
|
||||
*/
|
||||
public class FastDFSCmd {
|
||||
/**
|
||||
* 上传文件
|
||||
*/
|
||||
public static final byte STORAGE_PROTO_CMD_UPLOAD_FILE = 11;
|
||||
}
|
||||
+73
@@ -0,0 +1,73 @@
|
||||
package com.aivfo.dfs.client.core.fastDFS.constant;
|
||||
|
||||
/**
|
||||
* @author: wangyl
|
||||
* @date: 2023/5/4
|
||||
* @description: fastDFS 常量数据
|
||||
*/
|
||||
public class FastDFSConstant {
|
||||
/**
|
||||
* 连接超时时间
|
||||
*/
|
||||
public static final String PROP_KEY_CONNECT_TIMEOUT_IN_SECONDS = "fastdfs.connect_timeout_in_seconds";
|
||||
/**
|
||||
* 网络通讯超时时间
|
||||
*/
|
||||
public static final String PROP_KEY_NETWORK_TIMEOUT_IN_SECONDS = "fastdfs.network_timeout_in_seconds";
|
||||
/**
|
||||
* 字符集
|
||||
*/
|
||||
public static final String PROP_KEY_CHARSET = "fastdfs.charset";
|
||||
/**
|
||||
* http token
|
||||
*/
|
||||
public static final String PROP_KEY_HTTP_ANTI_STEAL_TOKEN = "fastdfs.http_anti_steal_token";
|
||||
/**
|
||||
* http密钥
|
||||
*/
|
||||
public static final String PROP_KEY_HTTP_SECRET_KEY = "fastdfs.http_secret_key";
|
||||
/**
|
||||
* http track 端口
|
||||
*/
|
||||
public static final String PROP_KEY_HTTP_TRACKER_HTTP_PORT = "fastdfs.http_tracker_http_port";
|
||||
/**
|
||||
* tracker服务列表,用“,”分割
|
||||
*/
|
||||
public static final String PROP_KEY_TRACKER_SERVERS = "fastdfs.tracker_servers";
|
||||
/**
|
||||
* 是否启动连接池
|
||||
*/
|
||||
public static final String PROP_KEY_CONNECTION_POOL_ENABLED = "fastdfs.connection_pool.enabled";
|
||||
/**
|
||||
* 连接池最大连接数量
|
||||
*/
|
||||
public static final String PROP_KEY_CONNECTION_POOL_MAX_COUNT_PER_ENTRY = "fastdfs.connection_pool.max_count_per_entry";
|
||||
/**
|
||||
* 连接池最大连接时间
|
||||
*/
|
||||
public static final String PROP_KEY_CONNECTION_POOL_MAX_IDLE_TIME = "fastdfs.connection_pool.max_idle_time";
|
||||
/**
|
||||
* 连接池最大等待时间
|
||||
*/
|
||||
public static final String PROP_KEY_CONNECTION_POOL_MAX_WAIT_TIME_IN_MS = "fastdfs.connection_pool.max_wait_time_in_ms";
|
||||
/**
|
||||
* 文件名字
|
||||
*/
|
||||
public static final String FILE_NAME = "fileName";
|
||||
/**
|
||||
* 文件后缀
|
||||
*/
|
||||
public static final String FILE_EXT_NAME = "fileExtName";
|
||||
/**
|
||||
* StoragePath的开头
|
||||
*/
|
||||
public final static String STORAGE_PATH_START = "M";
|
||||
/**
|
||||
* StoragePath的Data
|
||||
*/
|
||||
public final static String STORAGE_PATH_DATA = "data";
|
||||
/**
|
||||
* 上传路径结果分割后长度
|
||||
*/
|
||||
public final static int UPLOAD_FILE_RESULT_SPILT_PATH = 5;
|
||||
}
|
||||
+115
@@ -0,0 +1,115 @@
|
||||
package com.aivfo.dfs.client.core.fastDFS.properties;
|
||||
|
||||
import com.aivfo.dfs.client.core.fastDFS.constant.FastDFSConstant;
|
||||
import com.csource.fastdfs.ClientGlobal;
|
||||
import lombok.Data;
|
||||
import org.checkerframework.checker.units.qual.C;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Properties;
|
||||
|
||||
|
||||
/**
|
||||
* @author: wangyl
|
||||
* @date: 2023/4/27
|
||||
* @description: FastDFS配置
|
||||
*/
|
||||
@Data
|
||||
public class FastDFSProperties {
|
||||
/**
|
||||
* 默认开启
|
||||
*/
|
||||
private boolean enable = true;
|
||||
|
||||
/**
|
||||
* 连接超时时间
|
||||
*/
|
||||
private String connectTimeoutInSeconds = "";
|
||||
/**
|
||||
* 传输超时时间
|
||||
*/
|
||||
private String networkTimeoutInSeconds = "";
|
||||
/**
|
||||
* 字符集编码
|
||||
*/
|
||||
private String charset = "";
|
||||
/**
|
||||
* HTTP防盗链令牌
|
||||
*/
|
||||
private String httpAntiStealToken = "";
|
||||
/**
|
||||
* HTTP加密密钥
|
||||
*/
|
||||
private String httpSecretKey = "";
|
||||
/**
|
||||
* HTTP跟踪器端口
|
||||
*/
|
||||
private String httpTrackerHttpPort = "";
|
||||
/**
|
||||
* tracker服务器 多个用,分割
|
||||
*/
|
||||
private String trackerServers;
|
||||
/**
|
||||
* 连接池信息
|
||||
*/
|
||||
private ConnectionPool connectionPool = new ConnectionPool();
|
||||
|
||||
/**
|
||||
* storage Path
|
||||
*/
|
||||
private Map<String, List<String>> storagePath = new HashMap<>();
|
||||
|
||||
/**
|
||||
* @author: wangyl
|
||||
* @date: 2023/4/28
|
||||
* @description: 连接池配置
|
||||
*/
|
||||
@Data
|
||||
public static class ConnectionPool {
|
||||
/**
|
||||
* 是否启用连接池 默认启用
|
||||
*/
|
||||
private Boolean enabled = true;
|
||||
/**
|
||||
* 最大数量
|
||||
*/
|
||||
private String maxCountPerEntry = "";
|
||||
/**
|
||||
* 最大闲置时间
|
||||
*/
|
||||
private String maxIdleTime = "";
|
||||
/**
|
||||
* 最大等待时间(毫秒)
|
||||
*/
|
||||
private String maxWaitTimeInMs = "";
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* 转换成Properties对象初始化
|
||||
*
|
||||
* @param
|
||||
* @return java.util.Properties
|
||||
* @Date 2023/4/28
|
||||
* @Author wangyl
|
||||
*/
|
||||
public Properties ConversionToProperties() {
|
||||
Properties properties = new Properties();
|
||||
properties.setProperty(FastDFSConstant.PROP_KEY_CONNECT_TIMEOUT_IN_SECONDS, this.getConnectTimeoutInSeconds());
|
||||
properties.setProperty(FastDFSConstant.PROP_KEY_NETWORK_TIMEOUT_IN_SECONDS, this.getNetworkTimeoutInSeconds());
|
||||
properties.setProperty(FastDFSConstant.PROP_KEY_CHARSET, this.getCharset());
|
||||
properties.setProperty(FastDFSConstant.PROP_KEY_HTTP_ANTI_STEAL_TOKEN, this.getHttpAntiStealToken());
|
||||
properties.setProperty(FastDFSConstant.PROP_KEY_HTTP_SECRET_KEY, this.getHttpSecretKey());
|
||||
properties.setProperty(FastDFSConstant.PROP_KEY_HTTP_TRACKER_HTTP_PORT, this.getHttpTrackerHttpPort());
|
||||
properties.setProperty(FastDFSConstant.PROP_KEY_TRACKER_SERVERS, this.getTrackerServers());
|
||||
properties.setProperty(FastDFSConstant.PROP_KEY_CONNECTION_POOL_ENABLED, this.getConnectionPool().getEnabled().toString());
|
||||
properties.setProperty(FastDFSConstant.PROP_KEY_CONNECTION_POOL_MAX_COUNT_PER_ENTRY, this.getConnectionPool().getMaxCountPerEntry());
|
||||
properties.setProperty(FastDFSConstant.PROP_KEY_CONNECTION_POOL_MAX_IDLE_TIME, this.getConnectionPool().getMaxIdleTime());
|
||||
properties.setProperty(FastDFSConstant.PROP_KEY_CONNECTION_POOL_MAX_WAIT_TIME_IN_MS, this.getConnectionPool().getMaxWaitTimeInMs());
|
||||
return properties;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
+64
@@ -0,0 +1,64 @@
|
||||
package com.aivfo.dfs;
|
||||
|
||||
import com.aivfo.dfs.client.core.Client;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.boot.test.context.SpringBootTest;
|
||||
import org.springframework.context.annotation.ComponentScan;
|
||||
import org.springframework.context.annotation.PropertySource;
|
||||
|
||||
import java.io.FileOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.util.Map;
|
||||
|
||||
@SpringBootTest(classes = DfsTestApplication.class, webEnvironment = SpringBootTest.WebEnvironment.NONE)
|
||||
@PropertySource(value = "classpath:application.properties")
|
||||
@ComponentScan(basePackages = "com.aivfo.dfs")
|
||||
public class DfsTestApplication {
|
||||
@Autowired
|
||||
Client client;
|
||||
|
||||
@Test
|
||||
public void uploadFile() throws Exception {
|
||||
String s = client.uploadFile("C:\\Users\\95981\\Desktop\\wangyongliang.jpg");
|
||||
System.out.println(s);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void getFileReallyPath() throws Exception {
|
||||
String s = client.getFileReallyPath("group1/M01/00/00/wKgfWWRbZ-aAVncdABPRK3dgG_Q052.jpg");
|
||||
System.out.println(s);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void downloadFile() throws Exception {
|
||||
String a = "group1/M01/00/00/wKgfWWRbZ-aAVncdABPRK3dgG_Q052.jpg";
|
||||
FileOutputStream out = new FileOutputStream("C:\\Users\\95981\\Desktop\\03.jpg");
|
||||
client.downloadFile(a, (date, dateSize) -> {
|
||||
try {
|
||||
out.write(date, 0, dateSize);
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
return -1;
|
||||
}
|
||||
return 0;
|
||||
});
|
||||
out.close();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void downloadFile1() throws Exception {
|
||||
String a = "group1/M01/00/00/wKgfWWRbZ-aAVncdABPRK3dgG_Q052.jpg";
|
||||
FileOutputStream out = new FileOutputStream("C:\\Users\\95981\\Desktop\\04.jpg");
|
||||
byte[] bytes = client.downloadFile(a);
|
||||
out.write(bytes);
|
||||
out.close();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void getFileMeta() throws Exception {
|
||||
String a = "group1/M02/00/00/wKgfWWRbleaAWfVEABPRK3dgG_Q188.jpg";
|
||||
Map<String, String> fileMeta = client.getFileMeta(a);
|
||||
System.out.println(fileMeta);
|
||||
}
|
||||
}
|
||||
+8
@@ -0,0 +1,8 @@
|
||||
aivfo.dfs.fastdfs.enable=true
|
||||
aivfo.dfs.fastdfs.trackerServers=192.168.31.89:22122,192.168.31.89:22123
|
||||
aivfo.dfs.fastdfs.storagePath.group1[0]=/mnt/data01/image/group1/storaged01
|
||||
aivfo.dfs.fastdfs.storagePath.group1[1]=/mnt/data01/image/group1/storaged02
|
||||
aivfo.dfs.fastdfs.storagePath.group1[2]=/mnt/data01/image/group1/storaged03
|
||||
aivfo.dfs.fastdfs.storagePath.group2[0]=/mnt/data01/image/group1/storaged01
|
||||
aivfo.dfs.fastdfs.storagePath.group2[1]=/mnt/data01/image/group1/storaged02
|
||||
aivfo.dfs.fastdfs.storagePath.group2[2]=/mnt/data01/image/group1/storaged03
|
||||
+491
@@ -0,0 +1,491 @@
|
||||
package com.csource.common;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
/**
|
||||
* Freeware from:
|
||||
* Roedy Green
|
||||
* Canadian Mind Products
|
||||
* #327 - 964 Heywood Avenue
|
||||
* Victoria, BC Canada V8V 2Y5
|
||||
* tel:(250) 361-9093
|
||||
* mailto:roedy@mindprod.com
|
||||
*/
|
||||
|
||||
/**
|
||||
* Encode arbitrary binary into printable ASCII using BASE64 encoding.
|
||||
* very loosely based on the Base64 Reader by
|
||||
* Dr. Mark Thornton
|
||||
* Optrak Distribution Software Ltd.
|
||||
* http://www.optrak.co.uk
|
||||
* and Kevin Kelley's http://www.ruralnet.net/~kelley/java/Base64.java
|
||||
* <p>
|
||||
* Base64 is a way of encoding 8-bit characters using only ASCII printable
|
||||
* characters similar to UUENCODE. UUENCODE includes a filename where BASE64 does not.
|
||||
* The spec is described in RFC 2045. Base64 is a scheme where
|
||||
* 3 bytes are concatenated, then split to form 4 groups of 6-bits each; and
|
||||
* each 6-bits gets translated to an encoded printable ASCII character, via a
|
||||
* table lookup. An encoded string is therefore longer than the original by
|
||||
* about 1/3. The "=" character is used to pad the end. Base64 is used,
|
||||
* among other things, to encode the user:password string in an
|
||||
* Authorization: header for HTTP. Don't confuse Base64 with
|
||||
* x-www-form-urlencoded which is handled by
|
||||
* Java.net.URLEncoder.encode/decode
|
||||
* If you don't like this code, there is another implementation at http://www.ruffboy.com/download.htm
|
||||
* Sun has an undocumented method called sun.misc.Base64Encoder.encode.
|
||||
* You could use hex, simpler to code, but not as compact.
|
||||
* <p>
|
||||
* If you wanted to encode a giant file, you could do it in large chunks that
|
||||
* are even multiples of 3 bytes, except for the last chunk, and append the outputs.
|
||||
* <p>
|
||||
* To encode a string, rather than binary data java.net.URLEncoder may be better. See
|
||||
* printable characters in the Java glossary for a discussion of the differences.
|
||||
* <p>
|
||||
* version 1.4 2002 February 15 -- correct bugs with uneven line lengths,
|
||||
* allow you to configure line separator.
|
||||
* now need Base64 object and instance methods.
|
||||
* new mailing address.
|
||||
* version 1.3 2000 September 12 -- fix problems with estimating output length in encode
|
||||
* version 1.2 2000 September 09 -- now handles decode as well.
|
||||
* version 1.1 1999 December 04 -- more symmetrical encoding algorithm.
|
||||
* more accurate StringBuffer allocation size.
|
||||
* version 1.0 1999 December 03 -- posted in comp.lang.java.programmer.
|
||||
* Futures Streams or files.
|
||||
*/
|
||||
|
||||
public class Base64 {
|
||||
|
||||
/**
|
||||
* Marker value for chars we just ignore, e.g. \n \r high ascii
|
||||
*/
|
||||
static final int IGNORE = -1;
|
||||
/**
|
||||
* Marker for = trailing pad
|
||||
*/
|
||||
static final int PAD = -2;
|
||||
/**
|
||||
* used to disable test driver
|
||||
*/
|
||||
private static final boolean debug = true;
|
||||
/**
|
||||
* how we separate lines, e.g. \n, \r\n, \r etc.
|
||||
*/
|
||||
private String lineSeparator = System.getProperty("line.separator");
|
||||
/**
|
||||
* max chars per line, excluding lineSeparator. A multiple of 4.
|
||||
*/
|
||||
private int lineLength = 72;
|
||||
private char[] valueToChar = new char[64];
|
||||
/**
|
||||
* binary value encoded by a given letter of the alphabet 0..63
|
||||
*/
|
||||
private int[] charToValue = new int[256];
|
||||
private int[] charToPad = new int[4];
|
||||
|
||||
/* constructor */
|
||||
public Base64() {
|
||||
this.init('+', '/', '=');
|
||||
}
|
||||
|
||||
/* constructor */
|
||||
public Base64(char chPlus, char chSplash, char chPad, int lineLength) {
|
||||
this.init(chPlus, chSplash, chPad);
|
||||
this.lineLength = lineLength;
|
||||
}
|
||||
|
||||
public Base64(int lineLength) {
|
||||
this.lineLength = lineLength;
|
||||
}
|
||||
|
||||
/**
|
||||
* debug display array
|
||||
*/
|
||||
public static void show(byte[] b) {
|
||||
int count = 0;
|
||||
int rows = 0;
|
||||
|
||||
|
||||
for (int i = 0; i < b.length; i++) {
|
||||
if (count == 8) {
|
||||
System.out.print(" ");
|
||||
} else if (count == 16) {
|
||||
System.out.println("");
|
||||
count = 0;
|
||||
continue;
|
||||
}
|
||||
System.out.print(Integer.toHexString(b[i] & 0xFF).toUpperCase() + " ");
|
||||
count++;
|
||||
|
||||
}
|
||||
System.out.println();
|
||||
}
|
||||
|
||||
/**
|
||||
* debug display array
|
||||
*/
|
||||
public static void display(byte[] b) {
|
||||
for (int i = 0; i < b.length; i++) {
|
||||
System.out.print((char) b[i]);
|
||||
}
|
||||
System.out.println();
|
||||
}
|
||||
|
||||
/**
|
||||
* test driver
|
||||
*/
|
||||
public static void main(String[] args) {
|
||||
test();
|
||||
System.exit(1);
|
||||
|
||||
if (debug) {
|
||||
try {
|
||||
Base64 b64 = new Base64();
|
||||
String str = "agfrtu¿¦etʲ1234¼Ù´óerty¿Õ234·¢¿¦2344ʲµÄ";
|
||||
String str64 = "";
|
||||
|
||||
//encode
|
||||
str64 = b64.encode(str.getBytes());
|
||||
System.out.println(str64);
|
||||
|
||||
//decode
|
||||
byte[] theBytes = b64.decode(str64);
|
||||
show(theBytes);
|
||||
String rst = new String(theBytes);
|
||||
System.out.println(rst);
|
||||
System.out.println(str);
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
//getBytes(String charsetName);
|
||||
/*
|
||||
byte[] a = { (byte)0xfc, (byte)0x0f, (byte)0xc0};
|
||||
byte[] b = { (byte)0x03, (byte)0xf0, (byte)0x3f};
|
||||
byte[] c = { (byte)0x00, (byte)0x00, (byte)0x00};
|
||||
byte[] d = { (byte)0xff, (byte)0xff, (byte)0xff};
|
||||
byte[] e = { (byte)0xfc, (byte)0x0f, (byte)0xc0, (byte)1};
|
||||
byte[] f = { (byte)0xfc, (byte)0x0f, (byte)0xc0, (byte)1, (byte)2};
|
||||
byte[] g = { (byte)0xfc, (byte)0x0f, (byte)0xc0, (byte)1, (byte)2, (byte)3};
|
||||
byte[] h = "AAAAAAAAAAB".getBytes();
|
||||
|
||||
|
||||
|
||||
show(a);
|
||||
show(b);
|
||||
show(c);
|
||||
show(d);
|
||||
show(e);
|
||||
show(f);
|
||||
show(g);
|
||||
show(h);
|
||||
Base64 b64 = new Base64();
|
||||
show(b64.decode(b64.encode(a)));
|
||||
show(b64.decode(b64.encode(b)));
|
||||
show(b64.decode(b64.encode(c)));
|
||||
show(b64.decode(b64.encode(d)));
|
||||
show(b64.decode(b64.encode(e)));
|
||||
show(b64.decode(b64.encode(f)));
|
||||
show(b64.decode(b64.encode(g)));
|
||||
show(b64.decode(b64.encode(h)));
|
||||
b64.setLineLength(8);
|
||||
show((b64.encode(h)).getBytes());
|
||||
*/
|
||||
}
|
||||
}// end main
|
||||
|
||||
public static void test() {
|
||||
try {
|
||||
Base64 b64 = new Base64();
|
||||
|
||||
//encode
|
||||
//str64 = b64.encode(str.getBytes());
|
||||
//System.out.println(str64);
|
||||
|
||||
String str64 = "CwUEFYoAAAADjQMC7ELJiY6w05267ELJiY6w05267ELJiY6w05267ELJiY6w05267ELJiY6w05267ELJiY6w05267ELJiY6w05267ELJiY6w05267ELJiY6w05267ELJiY6w05267ELJiY6w05267ELJiY6w05267ELJiY6w05267ELJiY6w05267EI=";
|
||||
//decode
|
||||
byte[] theBytes = b64.decode(str64);
|
||||
show(theBytes);
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
/* initialise defaultValueToChar and defaultCharToValue tables */
|
||||
private void init(char chPlus, char chSplash, char chPad) {
|
||||
int index = 0;
|
||||
// build translate this.valueToChar table only once.
|
||||
// 0..25 -> 'A'..'Z'
|
||||
for (int i = 'A'; i <= 'Z'; i++) {
|
||||
this.valueToChar[index++] = (char) i;
|
||||
}
|
||||
|
||||
// 26..51 -> 'a'..'z'
|
||||
for (int i = 'a'; i <= 'z'; i++) {
|
||||
this.valueToChar[index++] = (char) i;
|
||||
}
|
||||
|
||||
// 52..61 -> '0'..'9'
|
||||
for (int i = '0'; i <= '9'; i++) {
|
||||
this.valueToChar[index++] = (char) i;
|
||||
}
|
||||
|
||||
this.valueToChar[index++] = chPlus;
|
||||
this.valueToChar[index++] = chSplash;
|
||||
|
||||
// build translate defaultCharToValue table only once.
|
||||
for (int i = 0; i < 256; i++) {
|
||||
this.charToValue[i] = IGNORE; // default is to ignore
|
||||
}
|
||||
|
||||
for (int i = 0; i < 64; i++) {
|
||||
this.charToValue[this.valueToChar[i]] = i;
|
||||
}
|
||||
|
||||
this.charToValue[chPad] = PAD;
|
||||
java.util.Arrays.fill(this.charToPad, chPad);
|
||||
}
|
||||
|
||||
/**
|
||||
* Encode an arbitrary array of bytes as Base64 printable ASCII.
|
||||
* It will be broken into lines of 72 chars each. The last line is not
|
||||
* terminated with a line separator.
|
||||
* The output will always have an even multiple of data characters,
|
||||
* exclusive of \n. It is padded out with =.
|
||||
*/
|
||||
public String encode(byte[] b) throws IOException {
|
||||
// Each group or partial group of 3 bytes becomes four chars
|
||||
// covered quotient
|
||||
int outputLength = ((b.length + 2) / 3) * 4;
|
||||
|
||||
// account for trailing newlines, on all but the very last line
|
||||
if (lineLength != 0) {
|
||||
int lines = (outputLength + lineLength - 1) / lineLength - 1;
|
||||
if (lines > 0) {
|
||||
outputLength += lines * lineSeparator.length();
|
||||
}
|
||||
}
|
||||
|
||||
// must be local for recursion to work.
|
||||
StringBuffer sb = new StringBuffer(outputLength);
|
||||
|
||||
// must be local for recursion to work.
|
||||
int linePos = 0;
|
||||
|
||||
// first deal with even multiples of 3 bytes.
|
||||
int len = (b.length / 3) * 3;
|
||||
int leftover = b.length - len;
|
||||
for (int i = 0; i < len; i += 3) {
|
||||
// Start a new line if next 4 chars won't fit on the current line
|
||||
// We can't encapsulete the following code since the variable need to
|
||||
// be local to this incarnation of encode.
|
||||
linePos += 4;
|
||||
if (linePos > lineLength) {
|
||||
if (lineLength != 0) {
|
||||
sb.append(lineSeparator);
|
||||
}
|
||||
linePos = 4;
|
||||
}
|
||||
|
||||
// get next three bytes in unsigned form lined up,
|
||||
// in big-endian order
|
||||
int combined = b[i + 0] & 0xff;
|
||||
combined <<= 8;
|
||||
combined |= b[i + 1] & 0xff;
|
||||
combined <<= 8;
|
||||
combined |= b[i + 2] & 0xff;
|
||||
|
||||
// break those 24 bits into a 4 groups of 6 bits,
|
||||
// working LSB to MSB.
|
||||
int c3 = combined & 0x3f;
|
||||
combined >>>= 6;
|
||||
int c2 = combined & 0x3f;
|
||||
combined >>>= 6;
|
||||
int c1 = combined & 0x3f;
|
||||
combined >>>= 6;
|
||||
int c0 = combined & 0x3f;
|
||||
|
||||
// Translate into the equivalent alpha character
|
||||
// emitting them in big-endian order.
|
||||
sb.append(valueToChar[c0]);
|
||||
sb.append(valueToChar[c1]);
|
||||
sb.append(valueToChar[c2]);
|
||||
sb.append(valueToChar[c3]);
|
||||
}
|
||||
|
||||
// deal with leftover bytes
|
||||
switch (leftover) {
|
||||
case 0:
|
||||
default:
|
||||
// nothing to do
|
||||
break;
|
||||
|
||||
case 1:
|
||||
// One leftover byte generates xx==
|
||||
// Start a new line if next 4 chars won't fit on the current line
|
||||
linePos += 4;
|
||||
if (linePos > lineLength) {
|
||||
|
||||
if (lineLength != 0) {
|
||||
sb.append(lineSeparator);
|
||||
}
|
||||
linePos = 4;
|
||||
}
|
||||
|
||||
// Handle this recursively with a faked complete triple.
|
||||
// Throw away last two chars and replace with ==
|
||||
sb.append(encode(new byte[]{b[len], 0, 0}
|
||||
).substring(0, 2));
|
||||
sb.append("==");
|
||||
break;
|
||||
|
||||
case 2:
|
||||
// Two leftover bytes generates xxx=
|
||||
// Start a new line if next 4 chars won't fit on the current line
|
||||
linePos += 4;
|
||||
if (linePos > lineLength) {
|
||||
if (lineLength != 0) {
|
||||
sb.append(lineSeparator);
|
||||
}
|
||||
linePos = 4;
|
||||
}
|
||||
// Handle this recursively with a faked complete triple.
|
||||
// Throw away last char and replace with =
|
||||
sb.append(encode(new byte[]{b[len], b[len + 1], 0}
|
||||
).substring(0, 3));
|
||||
sb.append("=");
|
||||
break;
|
||||
|
||||
} // end switch;
|
||||
|
||||
if (outputLength != sb.length()) {
|
||||
System.out.println("oops: minor program flaw: output length mis-estimated");
|
||||
System.out.println("estimate:" + outputLength);
|
||||
System.out.println("actual:" + sb.length());
|
||||
}
|
||||
return sb.toString();
|
||||
}// end encode
|
||||
|
||||
/**
|
||||
* decode a well-formed complete Base64 string back into an array of bytes.
|
||||
* It must have an even multiple of 4 data characters (not counting \n),
|
||||
* padded out with = as needed.
|
||||
*/
|
||||
public byte[] decodeAuto(String s) {
|
||||
int nRemain = s.length() % 4;
|
||||
if (nRemain == 0) {
|
||||
return this.decode(s);
|
||||
} else {
|
||||
return this.decode(s + new String(this.charToPad, 0, 4 - nRemain));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* decode a well-formed complete Base64 string back into an array of bytes.
|
||||
* It must have an even multiple of 4 data characters (not counting \n),
|
||||
* padded out with = as needed.
|
||||
*/
|
||||
public byte[] decode(String s) {
|
||||
|
||||
// estimate worst case size of output array, no embedded newlines.
|
||||
byte[] b = new byte[(s.length() / 4) * 3];
|
||||
|
||||
// tracks where we are in a cycle of 4 input chars.
|
||||
int cycle = 0;
|
||||
|
||||
// where we combine 4 groups of 6 bits and take apart as 3 groups of 8.
|
||||
int combined = 0;
|
||||
|
||||
// how many bytes we have prepared.
|
||||
int j = 0;
|
||||
// will be an even multiple of 4 chars, plus some embedded \n
|
||||
int len = s.length();
|
||||
int dummies = 0;
|
||||
for (int i = 0; i < len; i++) {
|
||||
|
||||
int c = s.charAt(i);
|
||||
int value = (c <= 255) ? charToValue[c] : IGNORE;
|
||||
// there are two magic values PAD (=) and IGNORE.
|
||||
switch (value) {
|
||||
case IGNORE:
|
||||
// e.g. \n, just ignore it.
|
||||
break;
|
||||
|
||||
case PAD:
|
||||
value = 0;
|
||||
dummies++;
|
||||
// fallthrough
|
||||
default:
|
||||
/* regular value character */
|
||||
switch (cycle) {
|
||||
case 0:
|
||||
combined = value;
|
||||
cycle = 1;
|
||||
break;
|
||||
|
||||
case 1:
|
||||
combined <<= 6;
|
||||
combined |= value;
|
||||
cycle = 2;
|
||||
break;
|
||||
|
||||
case 2:
|
||||
combined <<= 6;
|
||||
combined |= value;
|
||||
cycle = 3;
|
||||
break;
|
||||
|
||||
case 3:
|
||||
combined <<= 6;
|
||||
combined |= value;
|
||||
// we have just completed a cycle of 4 chars.
|
||||
// the four 6-bit values are in combined in big-endian order
|
||||
// peel them off 8 bits at a time working lsb to msb
|
||||
// to get our original 3 8-bit bytes back
|
||||
|
||||
b[j + 2] = (byte) combined;
|
||||
combined >>>= 8;
|
||||
b[j + 1] = (byte) combined;
|
||||
combined >>>= 8;
|
||||
b[j] = (byte) combined;
|
||||
j += 3;
|
||||
cycle = 0;
|
||||
break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
} // end for
|
||||
if (cycle != 0) {
|
||||
throw new ArrayIndexOutOfBoundsException("Input to decode not an even multiple of 4 characters; pad with =.");
|
||||
}
|
||||
j -= dummies;
|
||||
if (b.length != j) {
|
||||
byte[] b2 = new byte[j];
|
||||
System.arraycopy(b, 0, b2, 0, j);
|
||||
b = b2;
|
||||
}
|
||||
return b;
|
||||
|
||||
}// end decode
|
||||
|
||||
/**
|
||||
* determines how long the lines are that are generated by encode.
|
||||
* Ignored by decode.
|
||||
*
|
||||
* @param length 0 means no newlines inserted. Must be a multiple of 4.
|
||||
*/
|
||||
public void setLineLength(int length) {
|
||||
this.lineLength = (length / 4) * 4;
|
||||
}
|
||||
|
||||
/**
|
||||
* How lines are separated.
|
||||
* Ignored by decode.
|
||||
*
|
||||
* @param lineSeparator may be "" but not null.
|
||||
* Usually contains only a combination of chars \n and \r.
|
||||
* Could be any chars not in set A-Z a-z 0-9 + /.
|
||||
*/
|
||||
public void setLineSeparator(String lineSeparator) {
|
||||
this.lineSeparator = lineSeparator;
|
||||
}
|
||||
} // end Base64
|
||||
|
||||
+215
@@ -0,0 +1,215 @@
|
||||
/**
|
||||
* Copyright (C) 2008 Happy Fish / YuQing
|
||||
* <p>
|
||||
* FastDFS Java Client may be copied only under the terms of the GNU Lesser
|
||||
* General Public License (LGPL).
|
||||
* Please visit the FastDFS Home Page https://github.com/happyfish100/fastdfs for more detail.
|
||||
**/
|
||||
|
||||
package com.csource.common;
|
||||
|
||||
import java.io.*;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Hashtable;
|
||||
|
||||
/**
|
||||
* ini file reader / parser
|
||||
*
|
||||
* @author Happy Fish / YuQing
|
||||
* @version Version 1.0
|
||||
*/
|
||||
public class IniFileReader {
|
||||
private Hashtable paramTable;
|
||||
private String conf_filename;
|
||||
|
||||
/**
|
||||
* @param conf_filename config filename
|
||||
*/
|
||||
public IniFileReader(String conf_filename) throws IOException {
|
||||
this.conf_filename = conf_filename;
|
||||
loadFromFile(conf_filename);
|
||||
}
|
||||
|
||||
public static ClassLoader classLoader() {
|
||||
ClassLoader loader = Thread.currentThread().getContextClassLoader();
|
||||
if (loader == null) {
|
||||
loader = ClassLoader.getSystemClassLoader();
|
||||
}
|
||||
return loader;
|
||||
}
|
||||
|
||||
public static InputStream loadFromOsFileSystemOrClasspathAsStream(String filePath) {
|
||||
InputStream in = null;
|
||||
try {
|
||||
// 优先从文件系统路径加载
|
||||
if (new File(filePath).exists()) {
|
||||
in = new FileInputStream(filePath);
|
||||
//System.out.println("loadFrom...file path done");
|
||||
}
|
||||
// 从类路径加载
|
||||
else {
|
||||
in = classLoader().getResourceAsStream(filePath);
|
||||
//System.out.println("loadFrom...class path done");
|
||||
}
|
||||
} catch (Exception ex) {
|
||||
ex.printStackTrace();
|
||||
}
|
||||
return in;
|
||||
}
|
||||
|
||||
/**
|
||||
* get the config filename
|
||||
*
|
||||
* @return config filename
|
||||
*/
|
||||
public String getConfFilename() {
|
||||
return this.conf_filename;
|
||||
}
|
||||
|
||||
/**
|
||||
* get string value from config file
|
||||
*
|
||||
* @param name item name in config file
|
||||
* @return string value
|
||||
*/
|
||||
public String getStrValue(String name) {
|
||||
Object obj;
|
||||
obj = this.paramTable.get(name);
|
||||
if (obj == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
if (obj instanceof String) {
|
||||
return (String) obj;
|
||||
}
|
||||
|
||||
return (String) ((ArrayList) obj).get(0);
|
||||
}
|
||||
|
||||
/**
|
||||
* get int value from config file
|
||||
*
|
||||
* @param name item name in config file
|
||||
* @param default_value the default value
|
||||
* @return int value
|
||||
*/
|
||||
public int getIntValue(String name, int default_value) {
|
||||
String szValue = this.getStrValue(name);
|
||||
if (szValue == null) {
|
||||
return default_value;
|
||||
}
|
||||
|
||||
return Integer.parseInt(szValue);
|
||||
}
|
||||
|
||||
/**
|
||||
* get boolean value from config file
|
||||
*
|
||||
* @param name item name in config file
|
||||
* @param default_value the default value
|
||||
* @return boolean value
|
||||
*/
|
||||
public boolean getBoolValue(String name, boolean default_value) {
|
||||
String szValue = this.getStrValue(name);
|
||||
if (szValue == null) {
|
||||
return default_value;
|
||||
}
|
||||
|
||||
return szValue.equalsIgnoreCase("yes") || szValue.equalsIgnoreCase("on") ||
|
||||
szValue.equalsIgnoreCase("true") || szValue.equals("1");
|
||||
}
|
||||
|
||||
/**
|
||||
* get all values from config file
|
||||
*
|
||||
* @param name item name in config file
|
||||
* @return string values (array)
|
||||
*/
|
||||
public String[] getValues(String name) {
|
||||
Object obj;
|
||||
String[] values;
|
||||
|
||||
obj = this.paramTable.get(name);
|
||||
if (obj == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
if (obj instanceof String) {
|
||||
values = new String[1];
|
||||
values[0] = (String) obj;
|
||||
return values;
|
||||
}
|
||||
|
||||
Object[] objs = ((ArrayList) obj).toArray();
|
||||
values = new String[objs.length];
|
||||
System.arraycopy(objs, 0, values, 0, objs.length);
|
||||
return values;
|
||||
}
|
||||
|
||||
private void loadFromFile(String confFilePath) throws IOException {
|
||||
InputStream in = loadFromOsFileSystemOrClasspathAsStream(confFilePath);
|
||||
try {
|
||||
readToParamTable(in);
|
||||
} catch (Exception ex) {
|
||||
ex.printStackTrace();
|
||||
} finally {
|
||||
try {
|
||||
if (in != null) in.close();
|
||||
} catch (Exception ex) {
|
||||
ex.printStackTrace();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
private void readToParamTable(InputStream in) throws IOException {
|
||||
this.paramTable = new Hashtable();
|
||||
if (in == null) return;
|
||||
String line;
|
||||
String[] parts;
|
||||
String name;
|
||||
String value;
|
||||
Object obj;
|
||||
ArrayList valueList;
|
||||
InputStreamReader inReader = null;
|
||||
BufferedReader bufferedReader = null;
|
||||
try {
|
||||
inReader = new InputStreamReader(in);
|
||||
bufferedReader = new BufferedReader(inReader);
|
||||
while ((line = bufferedReader.readLine()) != null) {
|
||||
line = line.trim();
|
||||
if (line.length() == 0 || line.charAt(0) == '#') {
|
||||
continue;
|
||||
}
|
||||
parts = line.split("=", 2);
|
||||
if (parts.length != 2) {
|
||||
continue;
|
||||
}
|
||||
name = parts[0].trim();
|
||||
value = parts[1].trim();
|
||||
obj = this.paramTable.get(name);
|
||||
if (obj == null) {
|
||||
this.paramTable.put(name, value);
|
||||
} else if (obj instanceof String) {
|
||||
valueList = new ArrayList();
|
||||
valueList.add(obj);
|
||||
valueList.add(value);
|
||||
this.paramTable.put(name, valueList);
|
||||
} else {
|
||||
valueList = (ArrayList) obj;
|
||||
valueList.add(value);
|
||||
}
|
||||
}
|
||||
} catch (Exception ex) {
|
||||
ex.printStackTrace();
|
||||
} finally {
|
||||
try {
|
||||
if (bufferedReader != null) bufferedReader.close();
|
||||
if (inReader != null) inReader.close();
|
||||
} catch (Exception ex) {
|
||||
ex.printStackTrace();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
+24
@@ -0,0 +1,24 @@
|
||||
/*
|
||||
* Copyright (C) 2008 Happy Fish / YuQing
|
||||
*
|
||||
* FastDFS Java Client may be copied only under the terms of the GNU Lesser
|
||||
* General Public License (LGPL).
|
||||
* Please visit the FastDFS Home Page https://github.com/happyfish100/fastdfs for more detail.
|
||||
*/
|
||||
|
||||
package com.csource.common;
|
||||
|
||||
/**
|
||||
* My Exception
|
||||
*
|
||||
* @author Happy Fish / YuQing
|
||||
* @version Version 1.0
|
||||
*/
|
||||
public class MyException extends Exception {
|
||||
public MyException(String s, Exception e) {
|
||||
}
|
||||
|
||||
public MyException(String message) {
|
||||
super(message);
|
||||
}
|
||||
}
|
||||
+48
@@ -0,0 +1,48 @@
|
||||
/*
|
||||
* Copyright (C) 2008 Happy Fish / YuQing
|
||||
*
|
||||
* FastDFS Java Client may be copied only under the terms of the GNU Lesser
|
||||
* General Public License (LGPL).
|
||||
* Please visit the FastDFS Home Page https://github.com/happyfish100/fastdfs for more detail.
|
||||
*/
|
||||
|
||||
package com.csource.common;
|
||||
|
||||
/**
|
||||
* name(key) and value pair model
|
||||
*
|
||||
* @author Happy Fish / YuQing
|
||||
* @version Version 1.0
|
||||
*/
|
||||
public class NameValuePair {
|
||||
protected String name;
|
||||
protected String value;
|
||||
|
||||
public NameValuePair() {
|
||||
}
|
||||
|
||||
public NameValuePair(String name) {
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
public NameValuePair(String name, String value) {
|
||||
this.name = name;
|
||||
this.value = value;
|
||||
}
|
||||
|
||||
public String getName() {
|
||||
return this.name;
|
||||
}
|
||||
|
||||
public void setName(String name) {
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
public String getValue() {
|
||||
return this.value;
|
||||
}
|
||||
|
||||
public void setValue(String value) {
|
||||
this.value = value;
|
||||
}
|
||||
}
|
||||
+357
@@ -0,0 +1,357 @@
|
||||
/**
|
||||
* Copyright (C) 2008 Happy Fish / YuQing
|
||||
* <p>
|
||||
* FastDFS Java Client may be copied only under the terms of the GNU Lesser
|
||||
* General Public License (LGPL).
|
||||
* Please visit the FastDFS Home Page https://github.com/happyfish100/fastdfs for more detail.
|
||||
**/
|
||||
|
||||
package com.csource.fastdfs;
|
||||
|
||||
import com.csource.common.IniFileReader;
|
||||
import com.csource.common.MyException;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.net.InetSocketAddress;
|
||||
import java.net.Socket;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Properties;
|
||||
|
||||
/**
|
||||
* Global variables
|
||||
*
|
||||
* @author Happy Fish / YuQing
|
||||
* @version Version 1.11
|
||||
*/
|
||||
public class ClientGlobal {
|
||||
|
||||
public static final String CONF_KEY_CONNECT_TIMEOUT = "connect_timeout";
|
||||
public static final String CONF_KEY_NETWORK_TIMEOUT = "network_timeout";
|
||||
public static final String CONF_KEY_CHARSET = "charset";
|
||||
public static final String CONF_KEY_HTTP_ANTI_STEAL_TOKEN = "http.anti_steal_token";
|
||||
public static final String CONF_KEY_HTTP_SECRET_KEY = "http.secret_key";
|
||||
public static final String CONF_KEY_HTTP_TRACKER_HTTP_PORT = "http.tracker_http_port";
|
||||
public static final String CONF_KEY_TRACKER_SERVER = "tracker_server";
|
||||
public static final String PROP_KEY_CONNECT_TIMEOUT_IN_SECONDS = "fastdfs.connect_timeout_in_seconds";
|
||||
public static final String PROP_KEY_NETWORK_TIMEOUT_IN_SECONDS = "fastdfs.network_timeout_in_seconds";
|
||||
public static final String PROP_KEY_CHARSET = "fastdfs.charset";
|
||||
public static final String PROP_KEY_HTTP_ANTI_STEAL_TOKEN = "fastdfs.http_anti_steal_token";
|
||||
public static final String PROP_KEY_HTTP_SECRET_KEY = "fastdfs.http_secret_key";
|
||||
public static final String PROP_KEY_HTTP_TRACKER_HTTP_PORT = "fastdfs.http_tracker_http_port";
|
||||
public static final String PROP_KEY_TRACKER_SERVERS = "fastdfs.tracker_servers";
|
||||
|
||||
|
||||
public static final String PROP_KEY_CONNECTION_POOL_ENABLED = "fastdfs.connection_pool.enabled";
|
||||
public static final String PROP_KEY_CONNECTION_POOL_MAX_COUNT_PER_ENTRY = "fastdfs.connection_pool.max_count_per_entry";
|
||||
public static final String PROP_KEY_CONNECTION_POOL_MAX_IDLE_TIME = "fastdfs.connection_pool.max_idle_time";
|
||||
public static final String PROP_KEY_CONNECTION_POOL_MAX_WAIT_TIME_IN_MS = "fastdfs.connection_pool.max_wait_time_in_ms";
|
||||
|
||||
public static final int DEFAULT_CONNECT_TIMEOUT = 5; //second
|
||||
public static final int DEFAULT_NETWORK_TIMEOUT = 30; //second
|
||||
public static final String DEFAULT_CHARSET = "UTF-8";
|
||||
public static final boolean DEFAULT_HTTP_ANTI_STEAL_TOKEN = false;
|
||||
public static final String DEFAULT_HTTP_SECRET_KEY = "FastDFS1234567890";
|
||||
public static final int DEFAULT_HTTP_TRACKER_HTTP_PORT = 80;
|
||||
|
||||
public static final boolean DEFAULT_CONNECTION_POOL_ENABLED = true;
|
||||
public static final int DEFAULT_CONNECTION_POOL_MAX_COUNT_PER_ENTRY = 100;
|
||||
public static final int DEFAULT_CONNECTION_POOL_MAX_IDLE_TIME = 3600;//second
|
||||
public static final int DEFAULT_CONNECTION_POOL_MAX_WAIT_TIME_IN_MS = 1000;//millisecond
|
||||
|
||||
public static int g_connect_timeout = DEFAULT_CONNECT_TIMEOUT * 1000; //millisecond
|
||||
public static int g_network_timeout = DEFAULT_NETWORK_TIMEOUT * 1000; //millisecond
|
||||
public static String g_charset = DEFAULT_CHARSET;
|
||||
public static boolean g_anti_steal_token = DEFAULT_HTTP_ANTI_STEAL_TOKEN; //if anti-steal token
|
||||
public static String g_secret_key = DEFAULT_HTTP_SECRET_KEY; //generage token secret key
|
||||
public static int g_tracker_http_port = DEFAULT_HTTP_TRACKER_HTTP_PORT;
|
||||
|
||||
public static boolean g_connection_pool_enabled = DEFAULT_CONNECTION_POOL_ENABLED;
|
||||
public static int g_connection_pool_max_count_per_entry = DEFAULT_CONNECTION_POOL_MAX_COUNT_PER_ENTRY;
|
||||
public static int g_connection_pool_max_idle_time = DEFAULT_CONNECTION_POOL_MAX_IDLE_TIME * 1000; //millisecond
|
||||
public static int g_connection_pool_max_wait_time_in_ms = DEFAULT_CONNECTION_POOL_MAX_WAIT_TIME_IN_MS; //millisecond
|
||||
|
||||
public static TrackerGroup g_tracker_group;
|
||||
|
||||
private ClientGlobal() {
|
||||
}
|
||||
|
||||
/**
|
||||
* load global variables
|
||||
*
|
||||
* @param conf_filename config filename
|
||||
*/
|
||||
public static void init(String conf_filename) throws IOException, MyException {
|
||||
IniFileReader iniReader;
|
||||
String[] szTrackerServers;
|
||||
String[] parts;
|
||||
|
||||
iniReader = new IniFileReader(conf_filename);
|
||||
|
||||
g_connect_timeout = iniReader.getIntValue("connect_timeout", DEFAULT_CONNECT_TIMEOUT);
|
||||
if (g_connect_timeout < 0) {
|
||||
g_connect_timeout = DEFAULT_CONNECT_TIMEOUT;
|
||||
}
|
||||
g_connect_timeout *= 1000; //millisecond
|
||||
|
||||
g_network_timeout = iniReader.getIntValue("network_timeout", DEFAULT_NETWORK_TIMEOUT);
|
||||
if (g_network_timeout < 0) {
|
||||
g_network_timeout = DEFAULT_NETWORK_TIMEOUT;
|
||||
}
|
||||
g_network_timeout *= 1000; //millisecond
|
||||
|
||||
g_charset = iniReader.getStrValue("charset");
|
||||
if (g_charset == null || g_charset.length() == 0) {
|
||||
g_charset = "ISO8859-1";
|
||||
}
|
||||
|
||||
szTrackerServers = iniReader.getValues("tracker_server");
|
||||
if (szTrackerServers == null) {
|
||||
throw new MyException("item \"tracker_server\" in " + conf_filename + " not found");
|
||||
}
|
||||
|
||||
InetSocketAddress[] tracker_servers = new InetSocketAddress[szTrackerServers.length];
|
||||
for (int i = 0; i < szTrackerServers.length; i++) {
|
||||
parts = szTrackerServers[i].split("\\:", 2);
|
||||
if (parts.length != 2) {
|
||||
throw new MyException("the value of item \"tracker_server\" is invalid, the correct format is host:port");
|
||||
}
|
||||
|
||||
tracker_servers[i] = new InetSocketAddress(parts[0].trim(), Integer.parseInt(parts[1].trim()));
|
||||
}
|
||||
g_tracker_group = new TrackerGroup(tracker_servers);
|
||||
|
||||
g_tracker_http_port = iniReader.getIntValue("http.tracker_http_port", 80);
|
||||
g_anti_steal_token = iniReader.getBoolValue("http.anti_steal_token", false);
|
||||
if (g_anti_steal_token) {
|
||||
g_secret_key = iniReader.getStrValue("http.secret_key");
|
||||
}
|
||||
g_connection_pool_enabled = iniReader.getBoolValue("connection_pool.enabled", DEFAULT_CONNECTION_POOL_ENABLED);
|
||||
g_connection_pool_max_count_per_entry = iniReader.getIntValue("connection_pool.max_count_per_entry", DEFAULT_CONNECTION_POOL_MAX_COUNT_PER_ENTRY);
|
||||
g_connection_pool_max_idle_time = iniReader.getIntValue("connection_pool.max_idle_time", DEFAULT_CONNECTION_POOL_MAX_IDLE_TIME);
|
||||
if (g_connection_pool_max_idle_time < 0) {
|
||||
g_connection_pool_max_idle_time = DEFAULT_CONNECTION_POOL_MAX_IDLE_TIME;
|
||||
}
|
||||
g_connection_pool_max_idle_time *= 1000;
|
||||
g_connection_pool_max_wait_time_in_ms = iniReader.getIntValue("connection_pool.max_wait_time_in_ms", DEFAULT_CONNECTION_POOL_MAX_WAIT_TIME_IN_MS);
|
||||
if (g_connection_pool_max_wait_time_in_ms < 0) {
|
||||
g_connection_pool_max_wait_time_in_ms = DEFAULT_CONNECTION_POOL_MAX_WAIT_TIME_IN_MS;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* load from properties file
|
||||
*
|
||||
* @param propsFilePath properties file path, eg:
|
||||
* "fastdfs-client.properties"
|
||||
* "config/fastdfs-client.properties"
|
||||
* "/opt/fastdfs-client.properties"
|
||||
* "C:\\Users\\James\\config\\fastdfs-client.properties"
|
||||
* properties文件至少包含一个配置项 fastdfs.tracker_servers 例如:
|
||||
* fastdfs.tracker_servers = 10.0.11.245:22122,10.0.11.246:22122
|
||||
* server的IP和端口用冒号':'分隔
|
||||
* server之间用逗号','分隔
|
||||
*/
|
||||
public static void initByProperties(String propsFilePath) throws IOException, MyException {
|
||||
Properties props = new Properties();
|
||||
InputStream in = IniFileReader.loadFromOsFileSystemOrClasspathAsStream(propsFilePath);
|
||||
if (in != null) {
|
||||
props.load(in);
|
||||
}
|
||||
initByProperties(props);
|
||||
}
|
||||
|
||||
public static void initByProperties(Properties props) throws IOException, MyException {
|
||||
String trackerServersConf = props.getProperty(PROP_KEY_TRACKER_SERVERS);
|
||||
if (trackerServersConf == null || trackerServersConf.trim().length() == 0) {
|
||||
throw new MyException(String.format("configure item %s is required", PROP_KEY_TRACKER_SERVERS));
|
||||
}
|
||||
initByTrackers(trackerServersConf.trim());
|
||||
|
||||
String connectTimeoutInSecondsConf = props.getProperty(PROP_KEY_CONNECT_TIMEOUT_IN_SECONDS);
|
||||
String networkTimeoutInSecondsConf = props.getProperty(PROP_KEY_NETWORK_TIMEOUT_IN_SECONDS);
|
||||
String charsetConf = props.getProperty(PROP_KEY_CHARSET);
|
||||
String httpAntiStealTokenConf = props.getProperty(PROP_KEY_HTTP_ANTI_STEAL_TOKEN);
|
||||
String httpSecretKeyConf = props.getProperty(PROP_KEY_HTTP_SECRET_KEY);
|
||||
String httpTrackerHttpPortConf = props.getProperty(PROP_KEY_HTTP_TRACKER_HTTP_PORT);
|
||||
String poolEnabled = props.getProperty(PROP_KEY_CONNECTION_POOL_ENABLED);
|
||||
String poolMaxCountPerEntry = props.getProperty(PROP_KEY_CONNECTION_POOL_MAX_COUNT_PER_ENTRY);
|
||||
String poolMaxIdleTime = props.getProperty(PROP_KEY_CONNECTION_POOL_MAX_IDLE_TIME);
|
||||
String poolMaxWaitTimeInMS = props.getProperty(PROP_KEY_CONNECTION_POOL_MAX_WAIT_TIME_IN_MS);
|
||||
if (connectTimeoutInSecondsConf != null && connectTimeoutInSecondsConf.trim().length() != 0) {
|
||||
g_connect_timeout = Integer.parseInt(connectTimeoutInSecondsConf.trim()) * 1000;
|
||||
}
|
||||
if (networkTimeoutInSecondsConf != null && networkTimeoutInSecondsConf.trim().length() != 0) {
|
||||
g_network_timeout = Integer.parseInt(networkTimeoutInSecondsConf.trim()) * 1000;
|
||||
}
|
||||
if (charsetConf != null && charsetConf.trim().length() != 0) {
|
||||
g_charset = charsetConf.trim();
|
||||
}
|
||||
if (httpAntiStealTokenConf != null && httpAntiStealTokenConf.trim().length() != 0) {
|
||||
g_anti_steal_token = Boolean.parseBoolean(httpAntiStealTokenConf);
|
||||
}
|
||||
if (httpSecretKeyConf != null && httpSecretKeyConf.trim().length() != 0) {
|
||||
g_secret_key = httpSecretKeyConf.trim();
|
||||
}
|
||||
if (httpTrackerHttpPortConf != null && httpTrackerHttpPortConf.trim().length() != 0) {
|
||||
g_tracker_http_port = Integer.parseInt(httpTrackerHttpPortConf);
|
||||
}
|
||||
if (poolEnabled != null && poolEnabled.trim().length() != 0) {
|
||||
g_connection_pool_enabled = Boolean.parseBoolean(poolEnabled);
|
||||
}
|
||||
if (poolMaxCountPerEntry != null && poolMaxCountPerEntry.trim().length() != 0) {
|
||||
g_connection_pool_max_count_per_entry = Integer.parseInt(poolMaxCountPerEntry);
|
||||
}
|
||||
if (poolMaxIdleTime != null && poolMaxIdleTime.trim().length() != 0) {
|
||||
g_connection_pool_max_idle_time = Integer.parseInt(poolMaxIdleTime) * 1000;
|
||||
}
|
||||
if (poolMaxWaitTimeInMS != null && poolMaxWaitTimeInMS.trim().length() != 0) {
|
||||
g_connection_pool_max_wait_time_in_ms = Integer.parseInt(poolMaxWaitTimeInMS);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* load from properties file
|
||||
*
|
||||
* @param trackerServers 例如:"10.0.11.245:22122,10.0.11.246:22122"
|
||||
* server的IP和端口用冒号':'分隔
|
||||
* server之间用逗号','分隔
|
||||
*/
|
||||
public static void initByTrackers(String trackerServers) throws IOException, MyException {
|
||||
List<InetSocketAddress> list = new ArrayList<InetSocketAddress>();
|
||||
String spr1 = ",";
|
||||
String spr2 = ":";
|
||||
String[] arr1 = trackerServers.trim().split(spr1);
|
||||
for (String addrStr : arr1) {
|
||||
String[] arr2 = addrStr.trim().split(spr2);
|
||||
String host = arr2[0].trim();
|
||||
int port = Integer.parseInt(arr2[1].trim());
|
||||
list.add(new InetSocketAddress(host, port));
|
||||
}
|
||||
InetSocketAddress[] trackerAddresses = list.toArray(new InetSocketAddress[list.size()]);
|
||||
initByTrackers(trackerAddresses);
|
||||
}
|
||||
|
||||
public static void initByTrackers(InetSocketAddress[] trackerAddresses) throws IOException, MyException {
|
||||
g_tracker_group = new TrackerGroup(trackerAddresses);
|
||||
}
|
||||
|
||||
/**
|
||||
* construct Socket object
|
||||
*
|
||||
* @param ip_addr ip address or hostname
|
||||
* @param port port number
|
||||
* @return connected Socket object
|
||||
*/
|
||||
public static Socket getSocket(String ip_addr, int port) throws IOException {
|
||||
Socket sock = new Socket();
|
||||
sock.setSoTimeout(ClientGlobal.g_network_timeout);
|
||||
sock.connect(new InetSocketAddress(ip_addr, port), ClientGlobal.g_connect_timeout);
|
||||
return sock;
|
||||
}
|
||||
|
||||
/**
|
||||
* construct Socket object
|
||||
*
|
||||
* @param addr InetSocketAddress object, including ip address and port
|
||||
* @return connected Socket object
|
||||
*/
|
||||
public static Socket getSocket(InetSocketAddress addr) throws IOException {
|
||||
Socket sock = new Socket();
|
||||
sock.setReuseAddress(true);
|
||||
sock.setSoTimeout(ClientGlobal.g_network_timeout);
|
||||
sock.connect(addr, ClientGlobal.g_connect_timeout);
|
||||
return sock;
|
||||
}
|
||||
|
||||
public static int getG_connect_timeout() {
|
||||
return g_connect_timeout;
|
||||
}
|
||||
|
||||
public static void setG_connect_timeout(int connect_timeout) {
|
||||
ClientGlobal.g_connect_timeout = connect_timeout;
|
||||
}
|
||||
|
||||
public static int getG_network_timeout() {
|
||||
return g_network_timeout;
|
||||
}
|
||||
|
||||
public static void setG_network_timeout(int network_timeout) {
|
||||
ClientGlobal.g_network_timeout = network_timeout;
|
||||
}
|
||||
|
||||
public static String getG_charset() {
|
||||
return g_charset;
|
||||
}
|
||||
|
||||
public static void setG_charset(String charset) {
|
||||
ClientGlobal.g_charset = charset;
|
||||
}
|
||||
|
||||
public static int getG_tracker_http_port() {
|
||||
return g_tracker_http_port;
|
||||
}
|
||||
|
||||
public static void setG_tracker_http_port(int tracker_http_port) {
|
||||
ClientGlobal.g_tracker_http_port = tracker_http_port;
|
||||
}
|
||||
|
||||
public static boolean getG_anti_steal_token() {
|
||||
return g_anti_steal_token;
|
||||
}
|
||||
|
||||
public static boolean isG_anti_steal_token() {
|
||||
return g_anti_steal_token;
|
||||
}
|
||||
|
||||
public static void setG_anti_steal_token(boolean anti_steal_token) {
|
||||
ClientGlobal.g_anti_steal_token = anti_steal_token;
|
||||
}
|
||||
|
||||
public static String getG_secret_key() {
|
||||
return g_secret_key;
|
||||
}
|
||||
|
||||
public static void setG_secret_key(String secret_key) {
|
||||
ClientGlobal.g_secret_key = secret_key;
|
||||
}
|
||||
|
||||
public static TrackerGroup getG_tracker_group() {
|
||||
return g_tracker_group;
|
||||
}
|
||||
|
||||
public static void setG_tracker_group(TrackerGroup tracker_group) {
|
||||
ClientGlobal.g_tracker_group = tracker_group;
|
||||
}
|
||||
|
||||
public static boolean isG_connection_pool_enabled() {
|
||||
return g_connection_pool_enabled;
|
||||
}
|
||||
|
||||
public static String configInfo() {
|
||||
String trackerServers = "";
|
||||
if (g_tracker_group != null) {
|
||||
InetSocketAddress[] trackerAddresses = g_tracker_group.tracker_servers;
|
||||
for (InetSocketAddress inetSocketAddress : trackerAddresses) {
|
||||
if (trackerServers.length() > 0) trackerServers += ",";
|
||||
String address = inetSocketAddress.toString();
|
||||
trackerServers += address.startsWith("/") ? address.substring(1) : address;
|
||||
}
|
||||
}
|
||||
return "{"
|
||||
+ "\n g_connect_timeout(ms) = " + g_connect_timeout
|
||||
+ "\n g_network_timeout(ms) = " + g_network_timeout
|
||||
+ "\n g_charset = " + g_charset
|
||||
+ "\n g_anti_steal_token = " + g_anti_steal_token
|
||||
+ "\n g_secret_key = " + g_secret_key
|
||||
+ "\n g_tracker_http_port = " + g_tracker_http_port
|
||||
+ "\n g_connection_pool_enabled = " + g_connection_pool_enabled
|
||||
+ "\n g_connection_pool_max_count_per_entry = " + g_connection_pool_max_count_per_entry
|
||||
+ "\n g_connection_pool_max_idle_time(ms) = " + g_connection_pool_max_idle_time
|
||||
+ "\n g_connection_pool_max_wait_time_in_ms(ms) = " + g_connection_pool_max_wait_time_in_ms
|
||||
+ "\n trackerServers = " + trackerServers
|
||||
+ "\n}";
|
||||
}
|
||||
|
||||
}
|
||||
+29
@@ -0,0 +1,29 @@
|
||||
/**
|
||||
* Copyright (C) 2008 Happy Fish / YuQing
|
||||
* <p>
|
||||
* FastDFS Java Client may be copied only under the terms of the GNU Lesser
|
||||
* General Public License (LGPL).
|
||||
* Please visit the FastDFS Home Page https://github.com/happyfish100/fastdfs for more detail.
|
||||
*/
|
||||
|
||||
package com.csource.fastdfs;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
/**
|
||||
* Download file callback interface
|
||||
*
|
||||
* @author Happy Fish / YuQing
|
||||
* @version Version 1.4
|
||||
*/
|
||||
public interface DownloadCallback {
|
||||
/**
|
||||
* recv file content callback function, may be called more than once when the file downloaded
|
||||
*
|
||||
* @param file_size file size
|
||||
* @param data data buff
|
||||
* @param bytes data bytes
|
||||
* @return 0 success, return none zero(errno) if fail
|
||||
*/
|
||||
int recv(long file_size, byte[] data, int bytes) throws IOException;
|
||||
}
|
||||
+45
@@ -0,0 +1,45 @@
|
||||
package com.csource.fastdfs;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.OutputStream;
|
||||
|
||||
/**
|
||||
* Download file by stream (download callback class)
|
||||
*
|
||||
* @author zhouzezhong & Happy Fish / YuQing
|
||||
* @version Version 1.11
|
||||
*/
|
||||
public class DownloadStream implements DownloadCallback {
|
||||
private OutputStream out;
|
||||
private long currentBytes = 0;
|
||||
|
||||
public DownloadStream(OutputStream out) {
|
||||
super();
|
||||
this.out = out;
|
||||
}
|
||||
|
||||
/**
|
||||
* recv file content callback function, may be called more than once when the file downloaded
|
||||
*
|
||||
* @param fileSize file size
|
||||
* @param data data buff
|
||||
* @param bytes data bytes
|
||||
* @return 0 success, return none zero(errno) if fail
|
||||
*/
|
||||
@Override
|
||||
public int recv(long fileSize, byte[] data, int bytes) {
|
||||
try {
|
||||
out.write(data, 0, bytes);
|
||||
} catch (IOException ex) {
|
||||
ex.printStackTrace();
|
||||
return -1;
|
||||
}
|
||||
|
||||
currentBytes += bytes;
|
||||
if (this.currentBytes == fileSize) {
|
||||
this.currentBytes = 0;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
+175
@@ -0,0 +1,175 @@
|
||||
/**
|
||||
* Copyright (C) 2008 Happy Fish / YuQing
|
||||
* <p>
|
||||
* FastDFS Java Client may be copied only under the terms of the GNU Lesser
|
||||
* General Public License (LGPL).
|
||||
* Please visit the FastDFS Home Page https://github.com/happyfish100/fastdfs for more detail.
|
||||
*/
|
||||
|
||||
package com.csource.fastdfs;
|
||||
|
||||
import java.text.SimpleDateFormat;
|
||||
import java.util.Date;
|
||||
|
||||
/**
|
||||
* Server Info
|
||||
*
|
||||
* @author Happy Fish / YuQing
|
||||
* @version Version 1.23
|
||||
*/
|
||||
public class FileInfo {
|
||||
public static final short FILE_TYPE_NORMAL = 1;
|
||||
public static final short FILE_TYPE_APPENDER = 2;
|
||||
public static final short FILE_TYPE_SLAVE = 4;
|
||||
|
||||
protected boolean fetch_from_server;
|
||||
protected short file_type;
|
||||
protected String source_ip_addr;
|
||||
protected long file_size;
|
||||
protected Date create_timestamp;
|
||||
protected int crc32;
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
*
|
||||
* @param fetch_from_server if fetch from server flag
|
||||
* @param file_type the file type
|
||||
* @param file_size the file size
|
||||
* @param create_timestamp create timestamp in seconds
|
||||
* @param crc32 the crc32 signature
|
||||
* @param source_ip_addr the source storage ip address
|
||||
*/
|
||||
public FileInfo(boolean fetch_from_server, short file_type, long file_size,
|
||||
int create_timestamp, int crc32, String source_ip_addr) {
|
||||
this.fetch_from_server = fetch_from_server;
|
||||
this.file_type = file_type;
|
||||
this.file_size = file_size;
|
||||
this.create_timestamp = new Date(create_timestamp * 1000L);
|
||||
this.crc32 = crc32;
|
||||
this.source_ip_addr = source_ip_addr;
|
||||
}
|
||||
|
||||
/**
|
||||
* get the fetch_from_server flag
|
||||
*
|
||||
* @return the fetch_from_server flag
|
||||
*/
|
||||
public boolean getFetchFromServer() {
|
||||
return this.fetch_from_server;
|
||||
}
|
||||
|
||||
/**
|
||||
* set the fetch_from_server flag
|
||||
*
|
||||
* @param fetch_from_server the fetch from server flag
|
||||
*/
|
||||
public void setFetchFromServer(boolean fetch_from_server) {
|
||||
this.fetch_from_server = fetch_from_server;
|
||||
}
|
||||
|
||||
/**
|
||||
* get the file type
|
||||
*
|
||||
* @return the file type
|
||||
*/
|
||||
public short getFileType() {
|
||||
return this.file_type;
|
||||
}
|
||||
|
||||
/**
|
||||
* set the file type
|
||||
*
|
||||
* @param file_type the file type
|
||||
*/
|
||||
public void setFileType(short file_type) {
|
||||
this.file_type = file_type;
|
||||
}
|
||||
|
||||
/**
|
||||
* get the source ip address of the file uploaded to
|
||||
*
|
||||
* @return the source ip address of the file uploaded to
|
||||
*/
|
||||
public String getSourceIpAddr() {
|
||||
return this.source_ip_addr;
|
||||
}
|
||||
|
||||
/**
|
||||
* set the source ip address of the file uploaded to
|
||||
*
|
||||
* @param source_ip_addr the source ip address
|
||||
*/
|
||||
public void setSourceIpAddr(String source_ip_addr) {
|
||||
this.source_ip_addr = source_ip_addr;
|
||||
}
|
||||
|
||||
/**
|
||||
* get the file size
|
||||
*
|
||||
* @return the file size
|
||||
*/
|
||||
public long getFileSize() {
|
||||
return this.file_size;
|
||||
}
|
||||
|
||||
/**
|
||||
* set the file size
|
||||
*
|
||||
* @param file_size the file size
|
||||
*/
|
||||
public void setFileSize(long file_size) {
|
||||
this.file_size = file_size;
|
||||
}
|
||||
|
||||
/**
|
||||
* get the create timestamp of the file
|
||||
*
|
||||
* @return the create timestamp of the file
|
||||
*/
|
||||
public Date getCreateTimestamp() {
|
||||
return this.create_timestamp;
|
||||
}
|
||||
|
||||
/**
|
||||
* set the create timestamp of the file
|
||||
*
|
||||
* @param create_timestamp create timestamp in seconds
|
||||
*/
|
||||
public void setCreateTimestamp(int create_timestamp) {
|
||||
this.create_timestamp = new Date(create_timestamp * 1000L);
|
||||
}
|
||||
|
||||
/**
|
||||
* get the file CRC32 signature
|
||||
*
|
||||
* @return the file CRC32 signature
|
||||
*/
|
||||
public long getCrc32() {
|
||||
return this.crc32;
|
||||
}
|
||||
|
||||
/**
|
||||
* set the create timestamp of the file
|
||||
*
|
||||
* @param crc32 the crc32 signature
|
||||
*/
|
||||
public void setCrc32(int crc32) {
|
||||
this.crc32 = crc32;
|
||||
}
|
||||
|
||||
/**
|
||||
* to string
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
@Override
|
||||
public String toString() {
|
||||
SimpleDateFormat df = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
|
||||
return "fetch_from_server = " + this.fetch_from_server + ", " +
|
||||
"file_type = " + this.file_type + ", " +
|
||||
"source_ip_addr = " + this.source_ip_addr + ", " +
|
||||
"file_size = " + this.file_size + ", " +
|
||||
"create_timestamp = " + df.format(this.create_timestamp) + ", " +
|
||||
"crc32 = " + this.crc32;
|
||||
}
|
||||
}
|
||||
+506
@@ -0,0 +1,506 @@
|
||||
/**
|
||||
* Copyright (C) 2008 Happy Fish / YuQing
|
||||
* <p>
|
||||
* FastDFS Java Client may be copied only under the terms of the GNU Lesser
|
||||
* General Public License (LGPL).
|
||||
* Please visit the FastDFS Home Page https://github.com/happyfish100/fastdfs for more detail.
|
||||
**/
|
||||
|
||||
package com.csource.fastdfs;
|
||||
|
||||
|
||||
import com.csource.common.MyException;
|
||||
import com.csource.common.NameValuePair;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.UnsupportedEncodingException;
|
||||
import java.net.Socket;
|
||||
import java.security.NoSuchAlgorithmException;
|
||||
import java.util.Arrays;
|
||||
|
||||
/**
|
||||
* protocol common functions
|
||||
*
|
||||
* @author Happy Fish / YuQing
|
||||
* @version Version 1.18
|
||||
*/
|
||||
public class ProtoCommon {
|
||||
public static final byte FDFS_PROTO_CMD_QUIT = 82;
|
||||
public static final byte TRACKER_PROTO_CMD_SERVER_LIST_GROUP = 91;
|
||||
public static final byte TRACKER_PROTO_CMD_SERVER_LIST_STORAGE = 92;
|
||||
public static final byte TRACKER_PROTO_CMD_SERVER_DELETE_STORAGE = 93;
|
||||
public static final byte TRACKER_PROTO_CMD_SERVICE_QUERY_STORE_WITHOUT_GROUP_ONE = 101;
|
||||
public static final byte TRACKER_PROTO_CMD_SERVICE_QUERY_FETCH_ONE = 102;
|
||||
public static final byte TRACKER_PROTO_CMD_SERVICE_QUERY_UPDATE = 103;
|
||||
public static final byte TRACKER_PROTO_CMD_SERVICE_QUERY_STORE_WITH_GROUP_ONE = 104;
|
||||
public static final byte TRACKER_PROTO_CMD_SERVICE_QUERY_FETCH_ALL = 105;
|
||||
public static final byte TRACKER_PROTO_CMD_SERVICE_QUERY_STORE_WITHOUT_GROUP_ALL = 106;
|
||||
public static final byte TRACKER_PROTO_CMD_SERVICE_QUERY_STORE_WITH_GROUP_ALL = 107;
|
||||
public static final byte TRACKER_PROTO_CMD_RESP = 100;
|
||||
public static final byte FDFS_PROTO_CMD_ACTIVE_TEST = 111;
|
||||
public static final byte STORAGE_PROTO_CMD_UPLOAD_FILE = 11;
|
||||
public static final byte STORAGE_PROTO_CMD_DELETE_FILE = 12;
|
||||
public static final byte STORAGE_PROTO_CMD_SET_METADATA = 13;
|
||||
public static final byte STORAGE_PROTO_CMD_DOWNLOAD_FILE = 14;
|
||||
public static final byte STORAGE_PROTO_CMD_GET_METADATA = 15;
|
||||
public static final byte STORAGE_PROTO_CMD_UPLOAD_SLAVE_FILE = 21;
|
||||
public static final byte STORAGE_PROTO_CMD_QUERY_FILE_INFO = 22;
|
||||
public static final byte STORAGE_PROTO_CMD_UPLOAD_APPENDER_FILE = 23; //create appender file
|
||||
public static final byte STORAGE_PROTO_CMD_APPEND_FILE = 24; //append file
|
||||
public static final byte STORAGE_PROTO_CMD_MODIFY_FILE = 34; //modify appender file
|
||||
public static final byte STORAGE_PROTO_CMD_TRUNCATE_FILE = 36; //truncate appender file
|
||||
public static final byte STORAGE_PROTO_CMD_REGENERATE_APPENDER_FILENAME = 38; //rename appender file to normal file
|
||||
|
||||
public static final byte STORAGE_PROTO_CMD_RESP = TRACKER_PROTO_CMD_RESP;
|
||||
public static final byte FDFS_STORAGE_STATUS_INIT = 0;
|
||||
public static final byte FDFS_STORAGE_STATUS_WAIT_SYNC = 1;
|
||||
public static final byte FDFS_STORAGE_STATUS_SYNCING = 2;
|
||||
public static final byte FDFS_STORAGE_STATUS_IP_CHANGED = 3;
|
||||
public static final byte FDFS_STORAGE_STATUS_DELETED = 4;
|
||||
public static final byte FDFS_STORAGE_STATUS_OFFLINE = 5;
|
||||
public static final byte FDFS_STORAGE_STATUS_ONLINE = 6;
|
||||
public static final byte FDFS_STORAGE_STATUS_ACTIVE = 7;
|
||||
public static final byte FDFS_STORAGE_STATUS_NONE = 99;
|
||||
/**
|
||||
* for overwrite all old metadata
|
||||
*/
|
||||
public static final byte STORAGE_SET_METADATA_FLAG_OVERWRITE = 'O';
|
||||
/**
|
||||
* for replace, insert when the meta item not exist, otherwise update it
|
||||
*/
|
||||
public static final byte STORAGE_SET_METADATA_FLAG_MERGE = 'M';
|
||||
public static final int FDFS_PROTO_PKG_LEN_SIZE = 8;
|
||||
public static final int FDFS_PROTO_CMD_SIZE = 1;
|
||||
public static final int FDFS_GROUP_NAME_MAX_LEN = 16;
|
||||
public static final int FDFS_IPADDR_SIZE = 16;
|
||||
public static final int FDFS_DOMAIN_NAME_MAX_SIZE = 128;
|
||||
public static final int FDFS_VERSION_SIZE = 6;
|
||||
public static final int FDFS_STORAGE_ID_MAX_SIZE = 16;
|
||||
public static final String FDFS_RECORD_SEPERATOR = "\u0001";
|
||||
public static final String FDFS_FIELD_SEPERATOR = "\u0002";
|
||||
public static final int TRACKER_QUERY_STORAGE_FETCH_BODY_LEN = FDFS_GROUP_NAME_MAX_LEN
|
||||
+ FDFS_IPADDR_SIZE - 1 + FDFS_PROTO_PKG_LEN_SIZE;
|
||||
public static final int TRACKER_QUERY_STORAGE_STORE_BODY_LEN = FDFS_GROUP_NAME_MAX_LEN
|
||||
+ FDFS_IPADDR_SIZE + FDFS_PROTO_PKG_LEN_SIZE;
|
||||
public static final byte FDFS_FILE_EXT_NAME_MAX_LEN = 6;
|
||||
public static final byte FDFS_FILE_PREFIX_MAX_LEN = 16;
|
||||
public static final byte FDFS_FILE_PATH_LEN = 10;
|
||||
public static final byte FDFS_FILENAME_BASE64_LENGTH = 27;
|
||||
public static final byte FDFS_TRUNK_FILE_INFO_LEN = 16;
|
||||
public static final byte ERR_NO_ENOENT = 2;
|
||||
public static final byte ERR_NO_EIO = 5;
|
||||
public static final byte ERR_NO_EBUSY = 16;
|
||||
public static final byte ERR_NO_EINVAL = 22;
|
||||
public static final byte ERR_NO_ENOSPC = 28;
|
||||
public static final byte ECONNREFUSED = 61;
|
||||
public static final byte ERR_NO_EALREADY = 114;
|
||||
public static final long INFINITE_FILE_SIZE = 256 * 1024L * 1024 * 1024 * 1024 * 1024L;
|
||||
public static final long APPENDER_FILE_SIZE = INFINITE_FILE_SIZE;
|
||||
public static final long TRUNK_FILE_MARK_SIZE = 512 * 1024L * 1024 * 1024 * 1024 * 1024L;
|
||||
public static final long NORMAL_LOGIC_FILENAME_LENGTH = FDFS_FILE_PATH_LEN + FDFS_FILENAME_BASE64_LENGTH + FDFS_FILE_EXT_NAME_MAX_LEN + 1;
|
||||
public static final long TRUNK_LOGIC_FILENAME_LENGTH = NORMAL_LOGIC_FILENAME_LENGTH + FDFS_TRUNK_FILE_INFO_LEN;
|
||||
protected static final int PROTO_HEADER_CMD_INDEX = FDFS_PROTO_PKG_LEN_SIZE;
|
||||
protected static final int PROTO_HEADER_STATUS_INDEX = FDFS_PROTO_PKG_LEN_SIZE + 1;
|
||||
|
||||
private ProtoCommon() {
|
||||
}
|
||||
|
||||
public static String getStorageStatusCaption(byte status) {
|
||||
switch (status) {
|
||||
case FDFS_STORAGE_STATUS_INIT:
|
||||
return "INIT";
|
||||
case FDFS_STORAGE_STATUS_WAIT_SYNC:
|
||||
return "WAIT_SYNC";
|
||||
case FDFS_STORAGE_STATUS_SYNCING:
|
||||
return "SYNCING";
|
||||
case FDFS_STORAGE_STATUS_IP_CHANGED:
|
||||
return "IP_CHANGED";
|
||||
case FDFS_STORAGE_STATUS_DELETED:
|
||||
return "DELETED";
|
||||
case FDFS_STORAGE_STATUS_OFFLINE:
|
||||
return "OFFLINE";
|
||||
case FDFS_STORAGE_STATUS_ONLINE:
|
||||
return "ONLINE";
|
||||
case FDFS_STORAGE_STATUS_ACTIVE:
|
||||
return "ACTIVE";
|
||||
case FDFS_STORAGE_STATUS_NONE:
|
||||
return "NONE";
|
||||
default:
|
||||
return "UNKOWN";
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* pack header by FastDFS transfer protocol
|
||||
*
|
||||
* @param cmd which command to send
|
||||
* @param pkg_len package body length
|
||||
* @param errno status code, should be (byte)0
|
||||
* @return packed byte buffer
|
||||
*/
|
||||
public static byte[] packHeader(byte cmd, long pkg_len, byte errno) throws UnsupportedEncodingException {
|
||||
byte[] header;
|
||||
byte[] hex_len;
|
||||
|
||||
header = new byte[FDFS_PROTO_PKG_LEN_SIZE + 2];
|
||||
Arrays.fill(header, (byte) 0);
|
||||
|
||||
hex_len = ProtoCommon.long2buff(pkg_len);
|
||||
System.arraycopy(hex_len, 0, header, 0, hex_len.length);
|
||||
header[PROTO_HEADER_CMD_INDEX] = cmd;
|
||||
header[PROTO_HEADER_STATUS_INDEX] = errno;
|
||||
return header;
|
||||
}
|
||||
|
||||
/**
|
||||
* receive pack header
|
||||
*
|
||||
* @param in input stream
|
||||
* @param expect_cmd expect response command
|
||||
* @param expect_body_len expect response package body length
|
||||
* @return RecvHeaderInfo: errno and pkg body length
|
||||
*/
|
||||
public static RecvHeaderInfo recvHeader(InputStream in, byte expect_cmd, long expect_body_len) throws IOException {
|
||||
byte[] header;
|
||||
int bytes;
|
||||
long pkg_len;
|
||||
|
||||
header = new byte[FDFS_PROTO_PKG_LEN_SIZE + 2];
|
||||
|
||||
if ((bytes = in.read(header)) != header.length) {
|
||||
throw new IOException("recv package size " + bytes + " != " + header.length);
|
||||
}
|
||||
|
||||
if (header[PROTO_HEADER_CMD_INDEX] != expect_cmd) {
|
||||
throw new IOException("recv cmd: " + header[PROTO_HEADER_CMD_INDEX] + " is not correct, expect cmd: " + expect_cmd);
|
||||
}
|
||||
|
||||
if (header[PROTO_HEADER_STATUS_INDEX] != 0) {
|
||||
return new RecvHeaderInfo(header[PROTO_HEADER_STATUS_INDEX], 0);
|
||||
}
|
||||
|
||||
pkg_len = ProtoCommon.buff2long(header, 0);
|
||||
if (pkg_len < 0) {
|
||||
throw new IOException("recv body length: " + pkg_len + " < 0!");
|
||||
}
|
||||
|
||||
if (expect_body_len >= 0 && pkg_len != expect_body_len) {
|
||||
throw new IOException("recv body length: " + pkg_len + " is not correct, expect length: " + expect_body_len);
|
||||
}
|
||||
|
||||
return new RecvHeaderInfo((byte) 0, pkg_len);
|
||||
}
|
||||
|
||||
/**
|
||||
* receive whole pack
|
||||
*
|
||||
* @param in input stream
|
||||
* @param expect_cmd expect response command
|
||||
* @param expect_body_len expect response package body length
|
||||
* @return RecvPackageInfo: errno and reponse body(byte buff)
|
||||
*/
|
||||
public static RecvPackageInfo recvPackage(InputStream in, byte expect_cmd, long expect_body_len) throws IOException {
|
||||
RecvHeaderInfo header = recvHeader(in, expect_cmd, expect_body_len);
|
||||
if (header.errno != 0) {
|
||||
return new RecvPackageInfo(header.errno, null);
|
||||
}
|
||||
|
||||
byte[] body = new byte[(int) header.body_len];
|
||||
int totalBytes = 0;
|
||||
int remainBytes = (int) header.body_len;
|
||||
int bytes;
|
||||
|
||||
while (totalBytes < header.body_len) {
|
||||
if ((bytes = in.read(body, totalBytes, remainBytes)) < 0) {
|
||||
break;
|
||||
}
|
||||
|
||||
totalBytes += bytes;
|
||||
remainBytes -= bytes;
|
||||
}
|
||||
|
||||
if (totalBytes != header.body_len) {
|
||||
throw new IOException("recv package size " + totalBytes + " != " + header.body_len);
|
||||
}
|
||||
|
||||
return new RecvPackageInfo((byte) 0, body);
|
||||
}
|
||||
|
||||
/**
|
||||
* split metadata to name value pair array
|
||||
*
|
||||
* @param meta_buff metadata
|
||||
* @return name value pair array
|
||||
*/
|
||||
public static NameValuePair[] split_metadata(String meta_buff) {
|
||||
return split_metadata(meta_buff, FDFS_RECORD_SEPERATOR, FDFS_FIELD_SEPERATOR);
|
||||
}
|
||||
|
||||
/**
|
||||
* split metadata to name value pair array
|
||||
*
|
||||
* @param meta_buff metadata
|
||||
* @param recordSeperator record/row seperator
|
||||
* @param filedSeperator field/column seperator
|
||||
* @return name value pair array
|
||||
*/
|
||||
public static NameValuePair[] split_metadata(String meta_buff,
|
||||
String recordSeperator, String filedSeperator) {
|
||||
String[] rows;
|
||||
String[] cols;
|
||||
NameValuePair[] meta_list;
|
||||
|
||||
rows = meta_buff.split(recordSeperator);
|
||||
meta_list = new NameValuePair[rows.length];
|
||||
for (int i = 0; i < rows.length; i++) {
|
||||
cols = rows[i].split(filedSeperator, 2);
|
||||
meta_list[i] = new NameValuePair(cols[0]);
|
||||
if (cols.length == 2) {
|
||||
meta_list[i].setValue(cols[1]);
|
||||
}
|
||||
}
|
||||
|
||||
return meta_list;
|
||||
}
|
||||
|
||||
/**
|
||||
* pack metadata array to string
|
||||
*
|
||||
* @param meta_list metadata array
|
||||
* @return packed metadata
|
||||
*/
|
||||
public static String pack_metadata(NameValuePair[] meta_list) {
|
||||
if (meta_list.length == 0) {
|
||||
return "";
|
||||
}
|
||||
|
||||
StringBuffer sb = new StringBuffer(32 * meta_list.length);
|
||||
sb.append(meta_list[0].getName()).append(FDFS_FIELD_SEPERATOR).append(meta_list[0].getValue());
|
||||
for (int i = 1; i < meta_list.length; i++) {
|
||||
sb.append(FDFS_RECORD_SEPERATOR);
|
||||
sb.append(meta_list[i].getName()).append(FDFS_FIELD_SEPERATOR).append(meta_list[i].getValue());
|
||||
}
|
||||
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
/**
|
||||
* send quit command to server and close socket
|
||||
*
|
||||
* @param sock the Socket object
|
||||
*/
|
||||
public static void closeSocket(Socket sock) throws IOException {
|
||||
byte[] header;
|
||||
header = packHeader(FDFS_PROTO_CMD_QUIT, 0, (byte) 0);
|
||||
sock.getOutputStream().write(header);
|
||||
sock.close();
|
||||
}
|
||||
|
||||
/**
|
||||
* send ACTIVE_TEST command to server, test if network is ok and the server is alive
|
||||
*
|
||||
* @param sock the Socket object
|
||||
*/
|
||||
public static boolean activeTest(Socket sock) throws IOException {
|
||||
byte[] header;
|
||||
header = packHeader(FDFS_PROTO_CMD_ACTIVE_TEST, 0, (byte) 0);
|
||||
sock.getOutputStream().write(header);
|
||||
|
||||
RecvHeaderInfo headerInfo = recvHeader(sock.getInputStream(), TRACKER_PROTO_CMD_RESP, 0);
|
||||
return headerInfo.errno == 0 ? true : false;
|
||||
}
|
||||
|
||||
/**
|
||||
* long convert to buff (big-endian)
|
||||
*
|
||||
* @param n long number
|
||||
* @return 8 bytes buff
|
||||
*/
|
||||
public static byte[] long2buff(long n) {
|
||||
byte[] bs;
|
||||
|
||||
bs = new byte[8];
|
||||
bs[0] = (byte) ((n >> 56) & 0xFF);
|
||||
bs[1] = (byte) ((n >> 48) & 0xFF);
|
||||
bs[2] = (byte) ((n >> 40) & 0xFF);
|
||||
bs[3] = (byte) ((n >> 32) & 0xFF);
|
||||
bs[4] = (byte) ((n >> 24) & 0xFF);
|
||||
bs[5] = (byte) ((n >> 16) & 0xFF);
|
||||
bs[6] = (byte) ((n >> 8) & 0xFF);
|
||||
bs[7] = (byte) (n & 0xFF);
|
||||
|
||||
return bs;
|
||||
}
|
||||
|
||||
/**
|
||||
* buff convert to long
|
||||
*
|
||||
* @param bs the buffer (big-endian)
|
||||
* @param offset the start position based 0
|
||||
* @return long number
|
||||
*/
|
||||
public static long buff2long(byte[] bs, int offset) {
|
||||
return (((long) (bs[offset] >= 0 ? bs[offset] : 256 + bs[offset])) << 56) |
|
||||
(((long) (bs[offset + 1] >= 0 ? bs[offset + 1] : 256 + bs[offset + 1])) << 48) |
|
||||
(((long) (bs[offset + 2] >= 0 ? bs[offset + 2] : 256 + bs[offset + 2])) << 40) |
|
||||
(((long) (bs[offset + 3] >= 0 ? bs[offset + 3] : 256 + bs[offset + 3])) << 32) |
|
||||
(((long) (bs[offset + 4] >= 0 ? bs[offset + 4] : 256 + bs[offset + 4])) << 24) |
|
||||
(((long) (bs[offset + 5] >= 0 ? bs[offset + 5] : 256 + bs[offset + 5])) << 16) |
|
||||
(((long) (bs[offset + 6] >= 0 ? bs[offset + 6] : 256 + bs[offset + 6])) << 8) |
|
||||
((long) (bs[offset + 7] >= 0 ? bs[offset + 7] : 256 + bs[offset + 7]));
|
||||
}
|
||||
|
||||
/**
|
||||
* buff convert to int
|
||||
*
|
||||
* @param bs the buffer (big-endian)
|
||||
* @param offset the start position based 0
|
||||
* @return int number
|
||||
*/
|
||||
public static int buff2int(byte[] bs, int offset) {
|
||||
return (((int) (bs[offset] >= 0 ? bs[offset] : 256 + bs[offset])) << 24) |
|
||||
(((int) (bs[offset + 1] >= 0 ? bs[offset + 1] : 256 + bs[offset + 1])) << 16) |
|
||||
(((int) (bs[offset + 2] >= 0 ? bs[offset + 2] : 256 + bs[offset + 2])) << 8) |
|
||||
((int) (bs[offset + 3] >= 0 ? bs[offset + 3] : 256 + bs[offset + 3]));
|
||||
}
|
||||
|
||||
/**
|
||||
* buff convert to ip address
|
||||
*
|
||||
* @param bs the buffer (big-endian)
|
||||
* @param offset the start position based 0
|
||||
* @return ip address
|
||||
*/
|
||||
public static String getIpAddress(byte[] bs, int offset) {
|
||||
if (bs[0] == 0 || bs[3] == 0) //storage server ID
|
||||
{
|
||||
return "";
|
||||
}
|
||||
|
||||
int n;
|
||||
StringBuilder sbResult = new StringBuilder(16);
|
||||
for (int i = offset; i < offset + 4; i++) {
|
||||
n = (bs[i] >= 0) ? bs[i] : 256 + bs[i];
|
||||
if (sbResult.length() > 0) {
|
||||
sbResult.append(".");
|
||||
}
|
||||
sbResult.append(String.valueOf(n));
|
||||
}
|
||||
|
||||
return sbResult.toString();
|
||||
}
|
||||
|
||||
/**
|
||||
* md5 function
|
||||
*
|
||||
* @param source the input buffer
|
||||
* @return md5 string
|
||||
*/
|
||||
public static String md5(byte[] source) throws NoSuchAlgorithmException {
|
||||
char hexDigits[] = {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f'};
|
||||
java.security.MessageDigest md = java.security.MessageDigest.getInstance("MD5");
|
||||
md.update(source);
|
||||
byte tmp[] = md.digest();
|
||||
char str[] = new char[32];
|
||||
int k = 0;
|
||||
for (int i = 0; i < 16; i++) {
|
||||
str[k++] = hexDigits[tmp[i] >>> 4 & 0xf];
|
||||
str[k++] = hexDigits[tmp[i] & 0xf];
|
||||
}
|
||||
|
||||
return new String(str);
|
||||
}
|
||||
|
||||
/**
|
||||
* get token for file URL
|
||||
*
|
||||
* @param remote_filename the filename return by FastDFS server
|
||||
* @param ts unix timestamp, unit: second
|
||||
* @param secret_key the secret key
|
||||
* @return token string
|
||||
*/
|
||||
public static String getToken(String remote_filename, int ts, String secret_key) throws UnsupportedEncodingException, NoSuchAlgorithmException, MyException {
|
||||
byte[] bsFilename = remote_filename.getBytes(ClientGlobal.g_charset);
|
||||
byte[] bsKey = secret_key.getBytes(ClientGlobal.g_charset);
|
||||
byte[] bsTimestamp = (new Integer(ts)).toString().getBytes(ClientGlobal.g_charset);
|
||||
|
||||
byte[] buff = new byte[bsFilename.length + bsKey.length + bsTimestamp.length];
|
||||
System.arraycopy(bsFilename, 0, buff, 0, bsFilename.length);
|
||||
System.arraycopy(bsKey, 0, buff, bsFilename.length, bsKey.length);
|
||||
System.arraycopy(bsTimestamp, 0, buff, bsFilename.length + bsKey.length, bsTimestamp.length);
|
||||
|
||||
return md5(buff);
|
||||
}
|
||||
|
||||
/**
|
||||
* generate slave filename
|
||||
*
|
||||
* @param master_filename the master filename to generate the slave filename
|
||||
* @param prefix_name the prefix name to generate the slave filename
|
||||
* @param ext_name the extension name of slave filename, null for same as the master extension name
|
||||
* @return slave filename string
|
||||
*/
|
||||
public static String genSlaveFilename(String master_filename,
|
||||
String prefix_name, String ext_name) throws MyException {
|
||||
String true_ext_name;
|
||||
int dotIndex;
|
||||
|
||||
if (master_filename.length() < 28 + FDFS_FILE_EXT_NAME_MAX_LEN) {
|
||||
throw new MyException("master filename \"" + master_filename + "\" is invalid");
|
||||
}
|
||||
|
||||
dotIndex = master_filename.indexOf('.', master_filename.length() - (FDFS_FILE_EXT_NAME_MAX_LEN + 1));
|
||||
if (ext_name != null) {
|
||||
if (ext_name.length() == 0) {
|
||||
true_ext_name = "";
|
||||
} else if (ext_name.charAt(0) == '.') {
|
||||
true_ext_name = ext_name;
|
||||
} else {
|
||||
true_ext_name = "." + ext_name;
|
||||
}
|
||||
} else {
|
||||
if (dotIndex < 0) {
|
||||
true_ext_name = "";
|
||||
} else {
|
||||
true_ext_name = master_filename.substring(dotIndex);
|
||||
}
|
||||
}
|
||||
|
||||
if (true_ext_name.length() == 0 && prefix_name.equals("-m")) {
|
||||
throw new MyException("prefix_name \"" + prefix_name + "\" is invalid");
|
||||
}
|
||||
|
||||
if (dotIndex < 0) {
|
||||
return master_filename + prefix_name + true_ext_name;
|
||||
} else {
|
||||
return master_filename.substring(0, dotIndex) + prefix_name + true_ext_name;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* receive package info
|
||||
*/
|
||||
public static class RecvPackageInfo {
|
||||
public byte errno;
|
||||
public byte[] body;
|
||||
|
||||
public RecvPackageInfo(byte errno, byte[] body) {
|
||||
this.errno = errno;
|
||||
this.body = body;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* receive header info
|
||||
*/
|
||||
public static class RecvHeaderInfo {
|
||||
public byte errno;
|
||||
public long body_len;
|
||||
|
||||
public RecvHeaderInfo(byte errno, long body_len) {
|
||||
this.errno = errno;
|
||||
this.body_len = body_len;
|
||||
}
|
||||
}
|
||||
}
|
||||
+49
@@ -0,0 +1,49 @@
|
||||
/**
|
||||
* Copyright (C) 2008 Happy Fish / YuQing
|
||||
* <p>
|
||||
* FastDFS Java Client may be copied only under the terms of the GNU Lesser
|
||||
* General Public License (LGPL).
|
||||
* Please visit the FastDFS Home Page https://github.com/happyfish100/fastdfs for more detail.
|
||||
*/
|
||||
|
||||
package com.csource.fastdfs;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.lang.reflect.Array;
|
||||
|
||||
/**
|
||||
* C struct body decoder
|
||||
*
|
||||
* @author Happy Fish / YuQing
|
||||
* @version Version 1.17
|
||||
*/
|
||||
public class ProtoStructDecoder<T extends StructBase> {
|
||||
/**
|
||||
* Constructor
|
||||
*/
|
||||
public ProtoStructDecoder() {
|
||||
}
|
||||
|
||||
/**
|
||||
* decode byte buffer
|
||||
*/
|
||||
@SuppressWarnings("unchecked")
|
||||
public T[] decode(byte[] bs, Class<T> clazz, int fieldsTotalSize) throws Exception {
|
||||
if (bs.length % fieldsTotalSize != 0) {
|
||||
throw new IOException("byte array length: " + bs.length + " is invalid!");
|
||||
}
|
||||
|
||||
int count = bs.length / fieldsTotalSize;
|
||||
int offset;
|
||||
T[] results = (T[]) Array.newInstance(clazz, count);
|
||||
|
||||
offset = 0;
|
||||
for (int i = 0; i < results.length; i++) {
|
||||
results[i] = clazz.newInstance();
|
||||
results[i].setFields(bs, offset);
|
||||
offset += fieldsTotalSize;
|
||||
}
|
||||
|
||||
return results;
|
||||
}
|
||||
}
|
||||
+66
@@ -0,0 +1,66 @@
|
||||
/**
|
||||
* Copyright (C) 2008 Happy Fish / YuQing
|
||||
* <p>
|
||||
* FastDFS Java Client may be copied only under the terms of the GNU Lesser
|
||||
* General Public License (LGPL).
|
||||
* Please visit the FastDFS Home Page https://github.com/happyfish100/fastdfs for more detail.
|
||||
*/
|
||||
|
||||
package com.csource.fastdfs;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.net.InetSocketAddress;
|
||||
import java.net.Socket;
|
||||
|
||||
/**
|
||||
* Server Info
|
||||
*
|
||||
* @author Happy Fish / YuQing
|
||||
* @version Version 1.7
|
||||
*/
|
||||
public class ServerInfo {
|
||||
protected String ip_addr;
|
||||
protected int port;
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
*
|
||||
* @param ip_addr address of the server
|
||||
* @param port the port of the server
|
||||
*/
|
||||
public ServerInfo(String ip_addr, int port) {
|
||||
this.ip_addr = ip_addr;
|
||||
this.port = port;
|
||||
}
|
||||
|
||||
/**
|
||||
* return the ip address
|
||||
*
|
||||
* @return the ip address
|
||||
*/
|
||||
public String getIpAddr() {
|
||||
return this.ip_addr;
|
||||
}
|
||||
|
||||
/**
|
||||
* return the port of the server
|
||||
*
|
||||
* @return the port of the server
|
||||
*/
|
||||
public int getPort() {
|
||||
return this.port;
|
||||
}
|
||||
|
||||
/**
|
||||
* connect to server
|
||||
*
|
||||
* @return connected Socket object
|
||||
*/
|
||||
public Socket connect() throws IOException {
|
||||
Socket sock = new Socket();
|
||||
sock.setReuseAddress(true);
|
||||
sock.setSoTimeout(ClientGlobal.g_network_timeout);
|
||||
sock.connect(new InetSocketAddress(this.ip_addr, this.port), ClientGlobal.g_connect_timeout);
|
||||
return sock;
|
||||
}
|
||||
}
|
||||
+1807
File diff suppressed because it is too large
Load Diff
+766
@@ -0,0 +1,766 @@
|
||||
/**
|
||||
* Copyright (C) 2008 Happy Fish / YuQing
|
||||
* <p>
|
||||
* FastDFS Java Client may be copied only under the terms of the GNU Lesser
|
||||
* General Public License (LGPL).
|
||||
* Please visit the FastDFS Home Page https://github.com/happyfish100/fastdfs for more detail.
|
||||
*/
|
||||
|
||||
package com.csource.fastdfs;
|
||||
|
||||
|
||||
import com.csource.common.MyException;
|
||||
import com.csource.common.NameValuePair;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
/**
|
||||
* Storage client for 1 field file id: combined group name and filename
|
||||
* Note: the instance of this class is NOT thread safe !!!
|
||||
* if not necessary, do NOT set storage server instance
|
||||
*
|
||||
* @author Happy Fish / YuQing
|
||||
* @version Version 1.27
|
||||
*/
|
||||
public class StorageClient1 extends StorageClient {
|
||||
public static final String SPLIT_GROUP_NAME_AND_FILENAME_SEPERATOR = "/";
|
||||
|
||||
/**
|
||||
* constructor
|
||||
*/
|
||||
public StorageClient1() {
|
||||
super();
|
||||
}
|
||||
|
||||
/**
|
||||
* constructor with trackerServer
|
||||
*
|
||||
* @param trackerServer the tracker server, can be null
|
||||
*/
|
||||
public StorageClient1(TrackerServer trackerServer) {
|
||||
super(trackerServer);
|
||||
}
|
||||
|
||||
/**
|
||||
* constructor with trackerServer and storageServer
|
||||
* NOTE: if not necessary, do NOT set storage server instance
|
||||
*
|
||||
* @param trackerServer the tracker server, can be null
|
||||
* @param storageServer the storage server, can be null
|
||||
*/
|
||||
public StorageClient1(TrackerServer trackerServer, StorageServer storageServer) {
|
||||
super(trackerServer, storageServer);
|
||||
}
|
||||
|
||||
public static byte split_file_id(String file_id, String[] results) {
|
||||
int pos = file_id.indexOf(SPLIT_GROUP_NAME_AND_FILENAME_SEPERATOR);
|
||||
if ((pos <= 0) || (pos == file_id.length() - 1)) {
|
||||
return ProtoCommon.ERR_NO_EINVAL;
|
||||
}
|
||||
|
||||
results[0] = file_id.substring(0, pos); //group name
|
||||
results[1] = file_id.substring(pos + 1); //file name
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* upload file to storage server (by file name)
|
||||
*
|
||||
* @param local_filename local filename to upload
|
||||
* @param file_ext_name file ext name, do not include dot(.), null to extract ext name from the local filename
|
||||
* @param meta_list meta info array
|
||||
* @return file id(including group name and filename) if success, <br>
|
||||
* return null if fail
|
||||
*/
|
||||
public String upload_file1(String local_filename, String file_ext_name,
|
||||
NameValuePair[] meta_list) throws IOException, MyException {
|
||||
String parts[] = this.upload_file(local_filename, file_ext_name, meta_list);
|
||||
if (parts != null) {
|
||||
return parts[0] + SPLIT_GROUP_NAME_AND_FILENAME_SEPERATOR + parts[1];
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* upload file to storage server (by file name)
|
||||
*
|
||||
* @param group_name the group name to upload file to, can be empty
|
||||
* @param local_filename local filename to upload
|
||||
* @param file_ext_name file ext name, do not include dot(.), null to extract ext name from the local filename
|
||||
* @param meta_list meta info array
|
||||
* @return file id(including group name and filename) if success, <br>
|
||||
* return null if fail
|
||||
*/
|
||||
public String upload_file1(String group_name, String local_filename, String file_ext_name,
|
||||
NameValuePair[] meta_list) throws IOException, MyException {
|
||||
String parts[] = this.upload_file(group_name, local_filename, file_ext_name, meta_list);
|
||||
if (parts != null) {
|
||||
return parts[0] + SPLIT_GROUP_NAME_AND_FILENAME_SEPERATOR + parts[1];
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* upload file to storage server (by file buff)
|
||||
*
|
||||
* @param file_buff file content/buff
|
||||
* @param file_ext_name file ext name, do not include dot(.)
|
||||
* @param meta_list meta info array
|
||||
* @return file id(including group name and filename) if success, <br>
|
||||
* return null if fail
|
||||
*/
|
||||
public String upload_file1(byte[] file_buff, String file_ext_name,
|
||||
NameValuePair[] meta_list) throws IOException, MyException {
|
||||
String parts[] = this.upload_file(file_buff, file_ext_name, meta_list);
|
||||
if (parts != null) {
|
||||
return parts[0] + SPLIT_GROUP_NAME_AND_FILENAME_SEPERATOR + parts[1];
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* upload file to storage server (by file buff)
|
||||
*
|
||||
* @param group_name the group name to upload file to, can be empty
|
||||
* @param file_buff file content/buff
|
||||
* @param file_ext_name file ext name, do not include dot(.)
|
||||
* @param meta_list meta info array
|
||||
* @return file id(including group name and filename) if success, <br>
|
||||
* return null if fail
|
||||
*/
|
||||
public String upload_file1(String group_name, byte[] file_buff, String file_ext_name,
|
||||
NameValuePair[] meta_list) throws IOException, MyException {
|
||||
String parts[] = this.upload_file(group_name, file_buff, file_ext_name, meta_list);
|
||||
if (parts != null) {
|
||||
return parts[0] + SPLIT_GROUP_NAME_AND_FILENAME_SEPERATOR + parts[1];
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* upload file to storage server (by callback)
|
||||
*
|
||||
* @param group_name the group name to upload file to, can be empty
|
||||
* @param file_size the file size
|
||||
* @param callback the write data callback object
|
||||
* @param file_ext_name file ext name, do not include dot(.)
|
||||
* @param meta_list meta info array
|
||||
* @return file id(including group name and filename) if success, <br>
|
||||
* return null if fail
|
||||
*/
|
||||
public String upload_file1(String group_name, long file_size,
|
||||
UploadCallback callback, String file_ext_name,
|
||||
NameValuePair[] meta_list) throws IOException, MyException {
|
||||
String parts[] = this.upload_file(group_name, file_size, callback, file_ext_name, meta_list);
|
||||
if (parts != null) {
|
||||
return parts[0] + SPLIT_GROUP_NAME_AND_FILENAME_SEPERATOR + parts[1];
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* upload appender file to storage server (by file name)
|
||||
*
|
||||
* @param local_filename local filename to upload
|
||||
* @param file_ext_name file ext name, do not include dot(.), null to extract ext name from the local filename
|
||||
* @param meta_list meta info array
|
||||
* @return file id(including group name and filename) if success, <br>
|
||||
* return null if fail
|
||||
*/
|
||||
public String upload_appender_file1(String local_filename, String file_ext_name,
|
||||
NameValuePair[] meta_list) throws IOException, MyException {
|
||||
String parts[] = this.upload_appender_file(local_filename, file_ext_name, meta_list);
|
||||
if (parts != null) {
|
||||
return parts[0] + SPLIT_GROUP_NAME_AND_FILENAME_SEPERATOR + parts[1];
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* upload appender file to storage server (by file name)
|
||||
*
|
||||
* @param group_name the group name to upload file to, can be empty
|
||||
* @param local_filename local filename to upload
|
||||
* @param file_ext_name file ext name, do not include dot(.), null to extract ext name from the local filename
|
||||
* @param meta_list meta info array
|
||||
* @return file id(including group name and filename) if success, <br>
|
||||
* return null if fail
|
||||
*/
|
||||
public String upload_appender_file1(String group_name, String local_filename, String file_ext_name,
|
||||
NameValuePair[] meta_list) throws IOException, MyException {
|
||||
String parts[] = this.upload_appender_file(group_name, local_filename, file_ext_name, meta_list);
|
||||
if (parts != null) {
|
||||
return parts[0] + SPLIT_GROUP_NAME_AND_FILENAME_SEPERATOR + parts[1];
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* upload appender file to storage server (by file buff)
|
||||
*
|
||||
* @param file_buff file content/buff
|
||||
* @param file_ext_name file ext name, do not include dot(.)
|
||||
* @param meta_list meta info array
|
||||
* @return file id(including group name and filename) if success, <br>
|
||||
* return null if fail
|
||||
*/
|
||||
public String upload_appender_file1(byte[] file_buff, String file_ext_name,
|
||||
NameValuePair[] meta_list) throws IOException, MyException {
|
||||
String parts[] = this.upload_appender_file(file_buff, file_ext_name, meta_list);
|
||||
if (parts != null) {
|
||||
return parts[0] + SPLIT_GROUP_NAME_AND_FILENAME_SEPERATOR + parts[1];
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* upload appender file to storage server (by file buff)
|
||||
*
|
||||
* @param group_name the group name to upload file to, can be empty
|
||||
* @param file_buff file content/buff
|
||||
* @param file_ext_name file ext name, do not include dot(.)
|
||||
* @param meta_list meta info array
|
||||
* @return file id(including group name and filename) if success, <br>
|
||||
* return null if fail
|
||||
*/
|
||||
public String upload_appender_file1(String group_name, byte[] file_buff, String file_ext_name,
|
||||
NameValuePair[] meta_list) throws IOException, MyException {
|
||||
String parts[] = this.upload_appender_file(group_name, file_buff, file_ext_name, meta_list);
|
||||
if (parts != null) {
|
||||
return parts[0] + SPLIT_GROUP_NAME_AND_FILENAME_SEPERATOR + parts[1];
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* upload appender file to storage server (by callback)
|
||||
*
|
||||
* @param group_name the group name to upload file to, can be empty
|
||||
* @param file_size the file size
|
||||
* @param callback the write data callback object
|
||||
* @param file_ext_name file ext name, do not include dot(.)
|
||||
* @param meta_list meta info array
|
||||
* @return file id(including group name and filename) if success, <br>
|
||||
* return null if fail
|
||||
*/
|
||||
public String upload_appender_file1(String group_name, long file_size,
|
||||
UploadCallback callback, String file_ext_name,
|
||||
NameValuePair[] meta_list) throws IOException, MyException {
|
||||
String parts[] = this.upload_appender_file(group_name, file_size, callback, file_ext_name, meta_list);
|
||||
if (parts != null) {
|
||||
return parts[0] + SPLIT_GROUP_NAME_AND_FILENAME_SEPERATOR + parts[1];
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* upload file to storage server (by file name, slave file mode)
|
||||
*
|
||||
* @param master_file_id the master file id to generate the slave file
|
||||
* @param prefix_name the prefix name to generate the slave file
|
||||
* @param local_filename local filename to upload
|
||||
* @param file_ext_name file ext name, do not include dot(.), null to extract ext name from the local filename
|
||||
* @param meta_list meta info array
|
||||
* @return file id(including group name and filename) if success, <br>
|
||||
* return null if fail
|
||||
*/
|
||||
public String upload_file1(String master_file_id, String prefix_name,
|
||||
String local_filename, String file_ext_name, NameValuePair[] meta_list) throws IOException, MyException {
|
||||
String[] parts = new String[2];
|
||||
this.errno = this.split_file_id(master_file_id, parts);
|
||||
if (this.errno != 0) {
|
||||
return null;
|
||||
}
|
||||
|
||||
parts = this.upload_file(parts[0], parts[1], prefix_name,
|
||||
local_filename, file_ext_name, meta_list);
|
||||
if (parts != null) {
|
||||
return parts[0] + SPLIT_GROUP_NAME_AND_FILENAME_SEPERATOR + parts[1];
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* upload file to storage server (by file buff, slave file mode)
|
||||
*
|
||||
* @param master_file_id the master file id to generate the slave file
|
||||
* @param prefix_name the prefix name to generate the slave file
|
||||
* @param file_buff file content/buff
|
||||
* @param file_ext_name file ext name, do not include dot(.)
|
||||
* @param meta_list meta info array
|
||||
* @return file id(including group name and filename) if success, <br>
|
||||
* return null if fail
|
||||
*/
|
||||
public String upload_file1(String master_file_id, String prefix_name,
|
||||
byte[] file_buff, String file_ext_name, NameValuePair[] meta_list) throws IOException, MyException {
|
||||
String[] parts = new String[2];
|
||||
this.errno = this.split_file_id(master_file_id, parts);
|
||||
if (this.errno != 0) {
|
||||
return null;
|
||||
}
|
||||
|
||||
parts = this.upload_file(parts[0], parts[1], prefix_name, file_buff, file_ext_name, meta_list);
|
||||
if (parts != null) {
|
||||
return parts[0] + SPLIT_GROUP_NAME_AND_FILENAME_SEPERATOR + parts[1];
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* upload file to storage server (by file buff, slave file mode)
|
||||
*
|
||||
* @param master_file_id the master file id to generate the slave file
|
||||
* @param prefix_name the prefix name to generate the slave file
|
||||
* @param file_buff file content/buff
|
||||
* @param file_ext_name file ext name, do not include dot(.)
|
||||
* @param meta_list meta info array
|
||||
* @return file id(including group name and filename) if success, <br>
|
||||
* return null if fail
|
||||
*/
|
||||
public String upload_file1(String master_file_id, String prefix_name,
|
||||
byte[] file_buff, int offset, int length, String file_ext_name,
|
||||
NameValuePair[] meta_list) throws IOException, MyException {
|
||||
String[] parts = new String[2];
|
||||
this.errno = this.split_file_id(master_file_id, parts);
|
||||
if (this.errno != 0) {
|
||||
return null;
|
||||
}
|
||||
|
||||
parts = this.upload_file(parts[0], parts[1], prefix_name, file_buff,
|
||||
offset, length, file_ext_name, meta_list);
|
||||
if (parts != null) {
|
||||
return parts[0] + SPLIT_GROUP_NAME_AND_FILENAME_SEPERATOR + parts[1];
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* upload file to storage server (by callback)
|
||||
*
|
||||
* @param master_file_id the master file id to generate the slave file
|
||||
* @param prefix_name the prefix name to generate the slave file
|
||||
* @param file_size the file size
|
||||
* @param callback the write data callback object
|
||||
* @param file_ext_name file ext name, do not include dot(.)
|
||||
* @param meta_list meta info array
|
||||
* @return file id(including group name and filename) if success, <br>
|
||||
* return null if fail
|
||||
*/
|
||||
public String upload_file1(String master_file_id, String prefix_name, long file_size,
|
||||
UploadCallback callback, String file_ext_name,
|
||||
NameValuePair[] meta_list) throws IOException, MyException {
|
||||
String[] parts = new String[2];
|
||||
this.errno = this.split_file_id(master_file_id, parts);
|
||||
if (this.errno != 0) {
|
||||
return null;
|
||||
}
|
||||
|
||||
parts = this.upload_file(parts[0], parts[1], prefix_name, file_size, callback, file_ext_name, meta_list);
|
||||
if (parts != null) {
|
||||
return parts[0] + SPLIT_GROUP_NAME_AND_FILENAME_SEPERATOR + parts[1];
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* append file to storage server (by file name)
|
||||
*
|
||||
* @param appender_file_id the appender file id
|
||||
* @param local_filename local filename to append
|
||||
* @return 0 for success, != 0 for error (error no)
|
||||
*/
|
||||
public int append_file1(String appender_file_id, String local_filename) throws IOException, MyException {
|
||||
String[] parts = new String[2];
|
||||
this.errno = this.split_file_id(appender_file_id, parts);
|
||||
if (this.errno != 0) {
|
||||
return this.errno;
|
||||
}
|
||||
|
||||
return this.append_file(parts[0], parts[1], local_filename);
|
||||
}
|
||||
|
||||
/**
|
||||
* append file to storage server (by file buff)
|
||||
*
|
||||
* @param appender_file_id the appender file id
|
||||
* @param file_buff file content/buff
|
||||
* @return 0 for success, != 0 for error (error no)
|
||||
*/
|
||||
public int append_file1(String appender_file_id, byte[] file_buff) throws IOException, MyException {
|
||||
String[] parts = new String[2];
|
||||
this.errno = this.split_file_id(appender_file_id, parts);
|
||||
if (this.errno != 0) {
|
||||
return this.errno;
|
||||
}
|
||||
|
||||
return this.append_file(parts[0], parts[1], file_buff);
|
||||
}
|
||||
|
||||
/**
|
||||
* append file to storage server (by file buff)
|
||||
*
|
||||
* @param appender_file_id the appender file id
|
||||
* @param file_buff file content/buffer
|
||||
* @param offset start offset of the buffer
|
||||
* @param length the length of the buffer to append
|
||||
* @return 0 for success, != 0 for error (error no)
|
||||
*/
|
||||
public int append_file1(String appender_file_id, byte[] file_buff, int offset, int length) throws IOException, MyException {
|
||||
String[] parts = new String[2];
|
||||
this.errno = this.split_file_id(appender_file_id, parts);
|
||||
if (this.errno != 0) {
|
||||
return this.errno;
|
||||
}
|
||||
|
||||
return this.append_file(parts[0], parts[1], file_buff, offset, length);
|
||||
}
|
||||
|
||||
/**
|
||||
* append file to storage server (by callback)
|
||||
*
|
||||
* @param appender_file_id the appender file id
|
||||
* @param file_size the file size
|
||||
* @param callback the write data callback object
|
||||
* @return 0 for success, != 0 for error (error no)
|
||||
*/
|
||||
public int append_file1(String appender_file_id, long file_size, UploadCallback callback) throws IOException, MyException {
|
||||
String[] parts = new String[2];
|
||||
this.errno = this.split_file_id(appender_file_id, parts);
|
||||
if (this.errno != 0) {
|
||||
return this.errno;
|
||||
}
|
||||
|
||||
return this.append_file(parts[0], parts[1], file_size, callback);
|
||||
}
|
||||
|
||||
/**
|
||||
* modify appender file to storage server (by file name)
|
||||
*
|
||||
* @param appender_file_id the appender file id
|
||||
* @param file_offset the offset of appender file
|
||||
* @param local_filename local filename to append
|
||||
* @return 0 for success, != 0 for error (error no)
|
||||
*/
|
||||
public int modify_file1(String appender_file_id,
|
||||
long file_offset, String local_filename) throws IOException, MyException {
|
||||
String[] parts = new String[2];
|
||||
this.errno = this.split_file_id(appender_file_id, parts);
|
||||
if (this.errno != 0) {
|
||||
return this.errno;
|
||||
}
|
||||
|
||||
return this.modify_file(parts[0], parts[1], file_offset, local_filename);
|
||||
}
|
||||
|
||||
/**
|
||||
* modify appender file to storage server (by file buff)
|
||||
*
|
||||
* @param appender_file_id the appender file id
|
||||
* @param file_offset the offset of appender file
|
||||
* @param file_buff file content/buff
|
||||
* @return 0 for success, != 0 for error (error no)
|
||||
*/
|
||||
public int modify_file1(String appender_file_id,
|
||||
long file_offset, byte[] file_buff) throws IOException, MyException {
|
||||
String[] parts = new String[2];
|
||||
this.errno = this.split_file_id(appender_file_id, parts);
|
||||
if (this.errno != 0) {
|
||||
return this.errno;
|
||||
}
|
||||
|
||||
return this.modify_file(parts[0], parts[1], file_offset, file_buff);
|
||||
}
|
||||
|
||||
/**
|
||||
* modify appender file to storage server (by file buff)
|
||||
*
|
||||
* @param appender_file_id the appender file id
|
||||
* @param file_offset the offset of appender file
|
||||
* @param file_buff file content/buff
|
||||
* @param buffer_offset start offset of the buff
|
||||
* @param buffer_length the length of buff to modify
|
||||
* @return 0 for success, != 0 for error (error no)
|
||||
*/
|
||||
public int modify_file1(String appender_file_id,
|
||||
long file_offset, byte[] file_buff, int buffer_offset, int buffer_length) throws IOException, MyException {
|
||||
String[] parts = new String[2];
|
||||
this.errno = this.split_file_id(appender_file_id, parts);
|
||||
if (this.errno != 0) {
|
||||
return this.errno;
|
||||
}
|
||||
|
||||
return this.modify_file(parts[0], parts[1], file_offset,
|
||||
file_buff, buffer_offset, buffer_length);
|
||||
}
|
||||
|
||||
/**
|
||||
* modify appender file to storage server (by callback)
|
||||
*
|
||||
* @param appender_file_id the appender file id
|
||||
* @param file_offset the offset of appender file
|
||||
* @param modify_size the modify size
|
||||
* @param callback the write data callback object
|
||||
* @return 0 for success, != 0 for error (error no)
|
||||
*/
|
||||
public int modify_file1(String appender_file_id,
|
||||
long file_offset, long modify_size, UploadCallback callback) throws IOException, MyException {
|
||||
String[] parts = new String[2];
|
||||
this.errno = this.split_file_id(appender_file_id, parts);
|
||||
if (this.errno != 0) {
|
||||
return this.errno;
|
||||
}
|
||||
|
||||
return this.modify_file(parts[0], parts[1], file_offset, modify_size, callback);
|
||||
}
|
||||
|
||||
/**
|
||||
* regenerate filename for appender file
|
||||
*
|
||||
* @param appender_file_id the appender file id
|
||||
* @return the regenerated file id, return null if fail
|
||||
*/
|
||||
public String regenerate_appender_filename1(String appender_file_id) throws IOException, MyException {
|
||||
String[] parts = new String[2];
|
||||
this.errno = this.split_file_id(appender_file_id, parts);
|
||||
if (this.errno != 0) {
|
||||
return null;
|
||||
}
|
||||
|
||||
String[] new_parts = this.regenerate_appender_filename(parts[0], parts[1]);
|
||||
if (new_parts != null) {
|
||||
return new_parts[0] + SPLIT_GROUP_NAME_AND_FILENAME_SEPERATOR + new_parts[1];
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* delete file from storage server
|
||||
*
|
||||
* @param file_id the file id(including group name and filename)
|
||||
* @return 0 for success, none zero for fail (error code)
|
||||
*/
|
||||
public int delete_file1(String file_id) throws IOException, MyException {
|
||||
String[] parts = new String[2];
|
||||
this.errno = this.split_file_id(file_id, parts);
|
||||
if (this.errno != 0) {
|
||||
return this.errno;
|
||||
}
|
||||
|
||||
return this.delete_file(parts[0], parts[1]);
|
||||
}
|
||||
|
||||
/**
|
||||
* truncate appender file to size 0 from storage server
|
||||
*
|
||||
* @param appender_file_id the appender file id
|
||||
* @return 0 for success, none zero for fail (error code)
|
||||
*/
|
||||
public int truncate_file1(String appender_file_id) throws IOException, MyException {
|
||||
String[] parts = new String[2];
|
||||
this.errno = this.split_file_id(appender_file_id, parts);
|
||||
if (this.errno != 0) {
|
||||
return this.errno;
|
||||
}
|
||||
|
||||
return this.truncate_file(parts[0], parts[1]);
|
||||
}
|
||||
|
||||
/**
|
||||
* truncate appender file from storage server
|
||||
*
|
||||
* @param appender_file_id the appender file id
|
||||
* @param truncated_file_size truncated file size
|
||||
* @return 0 for success, none zero for fail (error code)
|
||||
*/
|
||||
public int truncate_file1(String appender_file_id, long truncated_file_size) throws IOException, MyException {
|
||||
String[] parts = new String[2];
|
||||
this.errno = this.split_file_id(appender_file_id, parts);
|
||||
if (this.errno != 0) {
|
||||
return this.errno;
|
||||
}
|
||||
|
||||
return this.truncate_file(parts[0], parts[1], truncated_file_size);
|
||||
}
|
||||
|
||||
/**
|
||||
* download file from storage server
|
||||
*
|
||||
* @param file_id the file id(including group name and filename)
|
||||
* @return file content/buffer, return null if fail
|
||||
*/
|
||||
public byte[] download_file1(String file_id) throws IOException, MyException {
|
||||
final long file_offset = 0;
|
||||
final long download_bytes = 0;
|
||||
|
||||
return this.download_file1(file_id, file_offset, download_bytes);
|
||||
}
|
||||
|
||||
/**
|
||||
* download file from storage server
|
||||
*
|
||||
* @param file_id the file id(including group name and filename)
|
||||
* @param file_offset the start offset of the file
|
||||
* @param download_bytes download bytes, 0 for remain bytes from offset
|
||||
* @return file content/buff, return null if fail
|
||||
*/
|
||||
public byte[] download_file1(String file_id, long file_offset, long download_bytes) throws IOException, MyException {
|
||||
String[] parts = new String[2];
|
||||
this.errno = this.split_file_id(file_id, parts);
|
||||
if (this.errno != 0) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return this.download_file(parts[0], parts[1], file_offset, download_bytes);
|
||||
}
|
||||
|
||||
/**
|
||||
* download file from storage server
|
||||
*
|
||||
* @param file_id the file id(including group name and filename)
|
||||
* @param local_filename the filename on local
|
||||
* @return 0 success, return none zero errno if fail
|
||||
*/
|
||||
public int download_file1(String file_id, String local_filename) throws IOException, MyException {
|
||||
final long file_offset = 0;
|
||||
final long download_bytes = 0;
|
||||
|
||||
return this.download_file1(file_id, file_offset, download_bytes, local_filename);
|
||||
}
|
||||
|
||||
/**
|
||||
* download file from storage server
|
||||
*
|
||||
* @param file_id the file id(including group name and filename)
|
||||
* @param file_offset the start offset of the file
|
||||
* @param download_bytes download bytes, 0 for remain bytes from offset
|
||||
* @param local_filename the filename on local
|
||||
* @return 0 success, return none zero errno if fail
|
||||
*/
|
||||
public int download_file1(String file_id, long file_offset, long download_bytes, String local_filename) throws IOException, MyException {
|
||||
String[] parts = new String[2];
|
||||
this.errno = this.split_file_id(file_id, parts);
|
||||
if (this.errno != 0) {
|
||||
return this.errno;
|
||||
}
|
||||
|
||||
return this.download_file(parts[0], parts[1], file_offset, download_bytes, local_filename);
|
||||
}
|
||||
|
||||
/**
|
||||
* download file from storage server
|
||||
*
|
||||
* @param file_id the file id(including group name and filename)
|
||||
* @param callback the callback object, will call callback.recv() when data arrive
|
||||
* @return 0 success, return none zero errno if fail
|
||||
*/
|
||||
public int download_file1(String file_id, DownloadCallback callback) throws IOException, MyException {
|
||||
final long file_offset = 0;
|
||||
final long download_bytes = 0;
|
||||
|
||||
return this.download_file1(file_id, file_offset, download_bytes, callback);
|
||||
}
|
||||
|
||||
/**
|
||||
* download file from storage server
|
||||
*
|
||||
* @param file_id the file id(including group name and filename)
|
||||
* @param file_offset the start offset of the file
|
||||
* @param download_bytes download bytes, 0 for remain bytes from offset
|
||||
* @param callback the callback object, will call callback.recv() when data arrive
|
||||
* @return 0 success, return none zero errno if fail
|
||||
*/
|
||||
public int download_file1(String file_id, long file_offset, long download_bytes, DownloadCallback callback) throws IOException, MyException {
|
||||
String[] parts = new String[2];
|
||||
this.errno = this.split_file_id(file_id, parts);
|
||||
if (this.errno != 0) {
|
||||
return this.errno;
|
||||
}
|
||||
|
||||
return this.download_file(parts[0], parts[1], file_offset, download_bytes, callback);
|
||||
}
|
||||
|
||||
/**
|
||||
* get all metadata items from storage server
|
||||
*
|
||||
* @param file_id the file id(including group name and filename)
|
||||
* @return meta info array, return null if fail
|
||||
*/
|
||||
public NameValuePair[] get_metadata1(String file_id) throws IOException, MyException {
|
||||
String[] parts = new String[2];
|
||||
this.errno = this.split_file_id(file_id, parts);
|
||||
if (this.errno != 0) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return this.get_metadata(parts[0], parts[1]);
|
||||
}
|
||||
|
||||
/**
|
||||
* set metadata items to storage server
|
||||
*
|
||||
* @param file_id the file id(including group name and filename)
|
||||
* @param meta_list meta item array
|
||||
* @param op_flag flag, can be one of following values: <br>
|
||||
* <ul><li> ProtoCommon.STORAGE_SET_METADATA_FLAG_OVERWRITE: overwrite all old
|
||||
* metadata items</li></ul>
|
||||
* <ul><li> ProtoCommon.STORAGE_SET_METADATA_FLAG_MERGE: merge, insert when
|
||||
* the metadata item not exist, otherwise update it</li></ul>
|
||||
* @return 0 for success, !=0 fail (error code)
|
||||
*/
|
||||
public int set_metadata1(String file_id, NameValuePair[] meta_list, byte op_flag) throws IOException, MyException {
|
||||
String[] parts = new String[2];
|
||||
this.errno = this.split_file_id(file_id, parts);
|
||||
if (this.errno != 0) {
|
||||
return this.errno;
|
||||
}
|
||||
|
||||
return this.set_metadata(parts[0], parts[1], meta_list, op_flag);
|
||||
}
|
||||
|
||||
/**
|
||||
* get file info from storage server
|
||||
*
|
||||
* @param file_id the file id(including group name and filename)
|
||||
* @return FileInfo object for success, return null for fail
|
||||
*/
|
||||
public FileInfo query_file_info1(String file_id) throws IOException, MyException {
|
||||
String[] parts = new String[2];
|
||||
this.errno = this.split_file_id(file_id, parts);
|
||||
if (this.errno != 0) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return this.query_file_info(parts[0], parts[1]);
|
||||
}
|
||||
|
||||
/**
|
||||
* get file info decoded from filename
|
||||
*
|
||||
* @param file_id the file id(including group name and filename)
|
||||
* @return FileInfo object for success, return null for fail
|
||||
*/
|
||||
public FileInfo get_file_info1(String file_id) throws IOException, MyException {
|
||||
String[] parts = new String[2];
|
||||
this.errno = this.split_file_id(file_id, parts);
|
||||
if (this.errno != 0) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return this.get_file_info(parts[0], parts[1]);
|
||||
}
|
||||
}
|
||||
+57
@@ -0,0 +1,57 @@
|
||||
/**
|
||||
* Copyright (C) 2008 Happy Fish / YuQing
|
||||
* <p>
|
||||
* FastDFS Java Client may be copied only under the terms of the GNU Lesser
|
||||
* General Public License (LGPL).
|
||||
* Please visit the FastDFS Home Page https://github.com/happyfish100/fastdfs for more detail.
|
||||
*/
|
||||
|
||||
package com.csource.fastdfs;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.net.InetSocketAddress;
|
||||
|
||||
/**
|
||||
* Storage Server Info
|
||||
*
|
||||
* @author Happy Fish / YuQing
|
||||
* @version Version 1.11
|
||||
*/
|
||||
public class StorageServer extends TrackerServer {
|
||||
protected int store_path_index = 0;
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
*
|
||||
* @param ip_addr the ip address of storage server
|
||||
* @param port the port of storage server
|
||||
* @param store_path the store path index on the storage server
|
||||
*/
|
||||
public StorageServer(String ip_addr, int port, int store_path) throws IOException {
|
||||
super(new InetSocketAddress(ip_addr, port));
|
||||
this.store_path_index = store_path;
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
*
|
||||
* @param ip_addr the ip address of storage server
|
||||
* @param port the port of storage server
|
||||
* @param store_path the store path index on the storage server
|
||||
*/
|
||||
public StorageServer(String ip_addr, int port, byte store_path) throws IOException {
|
||||
super(new InetSocketAddress(ip_addr, port));
|
||||
if (store_path < 0) {
|
||||
this.store_path_index = 256 + store_path;
|
||||
} else {
|
||||
this.store_path_index = store_path;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the store path index on the storage server
|
||||
*/
|
||||
public int getStorePathIndex() {
|
||||
return this.store_path_index;
|
||||
}
|
||||
}
|
||||
+73
@@ -0,0 +1,73 @@
|
||||
/**
|
||||
* Copyright (C) 2008 Happy Fish / YuQing
|
||||
* <p>
|
||||
* FastDFS Java Client may be copied only under the terms of the GNU Lesser
|
||||
* General Public License (LGPL).
|
||||
* Please visit the FastDFS Home Page https://github.com/happyfish100/fastdfs for more detail.
|
||||
*/
|
||||
|
||||
package com.csource.fastdfs;
|
||||
|
||||
import java.io.UnsupportedEncodingException;
|
||||
import java.util.Date;
|
||||
|
||||
/**
|
||||
* C struct body decoder
|
||||
*
|
||||
* @author Happy Fish / YuQing
|
||||
* @version Version 1.17
|
||||
*/
|
||||
public abstract class StructBase {
|
||||
/**
|
||||
* set fields
|
||||
*
|
||||
* @param bs byte array
|
||||
* @param offset start offset
|
||||
*/
|
||||
public abstract void setFields(byte[] bs, int offset);
|
||||
|
||||
protected String stringValue(byte[] bs, int offset, FieldInfo filedInfo) {
|
||||
try {
|
||||
return (new String(bs, offset + filedInfo.offset, filedInfo.size, ClientGlobal.g_charset)).trim();
|
||||
} catch (UnsupportedEncodingException ex) {
|
||||
ex.printStackTrace();
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
protected long longValue(byte[] bs, int offset, FieldInfo filedInfo) {
|
||||
return ProtoCommon.buff2long(bs, offset + filedInfo.offset);
|
||||
}
|
||||
|
||||
protected int intValue(byte[] bs, int offset, FieldInfo filedInfo) {
|
||||
return (int) ProtoCommon.buff2long(bs, offset + filedInfo.offset);
|
||||
}
|
||||
|
||||
protected int int32Value(byte[] bs, int offset, FieldInfo filedInfo) {
|
||||
return ProtoCommon.buff2int(bs, offset + filedInfo.offset);
|
||||
}
|
||||
|
||||
protected byte byteValue(byte[] bs, int offset, FieldInfo filedInfo) {
|
||||
return bs[offset + filedInfo.offset];
|
||||
}
|
||||
|
||||
protected boolean booleanValue(byte[] bs, int offset, FieldInfo filedInfo) {
|
||||
return bs[offset + filedInfo.offset] != 0;
|
||||
}
|
||||
|
||||
protected Date dateValue(byte[] bs, int offset, FieldInfo filedInfo) {
|
||||
return new Date(ProtoCommon.buff2long(bs, offset + filedInfo.offset) * 1000);
|
||||
}
|
||||
|
||||
protected static class FieldInfo {
|
||||
protected String name;
|
||||
protected int offset;
|
||||
protected int size;
|
||||
|
||||
public FieldInfo(String name, int offset, int size) {
|
||||
this.name = name;
|
||||
this.offset = offset;
|
||||
this.size = size;
|
||||
}
|
||||
}
|
||||
}
|
||||
+225
@@ -0,0 +1,225 @@
|
||||
/**
|
||||
* Copyright (C) 2008 Happy Fish / YuQing
|
||||
* <p>
|
||||
* FastDFS Java Client may be copied only under the terms of the GNU Lesser
|
||||
* General Public License (LGPL).
|
||||
* Please visit the FastDFS Home Page https://github.com/happyfish100/fastdfs for more detail.
|
||||
*/
|
||||
|
||||
package com.csource.fastdfs;
|
||||
|
||||
/**
|
||||
* C struct body decoder
|
||||
*
|
||||
* @author Happy Fish / YuQing
|
||||
* @version Version 1.18
|
||||
*/
|
||||
public class StructGroupStat extends StructBase {
|
||||
protected static final int FIELD_INDEX_GROUP_NAME = 0;
|
||||
protected static final int FIELD_INDEX_TOTAL_MB = 1;
|
||||
protected static final int FIELD_INDEX_FREE_MB = 2;
|
||||
protected static final int FIELD_INDEX_TRUNK_FREE_MB = 3;
|
||||
protected static final int FIELD_INDEX_STORAGE_COUNT = 4;
|
||||
protected static final int FIELD_INDEX_STORAGE_PORT = 5;
|
||||
protected static final int FIELD_INDEX_STORAGE_HTTP_PORT = 6;
|
||||
protected static final int FIELD_INDEX_ACTIVE_COUNT = 7;
|
||||
protected static final int FIELD_INDEX_CURRENT_WRITE_SERVER = 8;
|
||||
protected static final int FIELD_INDEX_STORE_PATH_COUNT = 9;
|
||||
protected static final int FIELD_INDEX_SUBDIR_COUNT_PER_PATH = 10;
|
||||
protected static final int FIELD_INDEX_CURRENT_TRUNK_FILE_ID = 11;
|
||||
|
||||
protected static int fieldsTotalSize;
|
||||
protected static FieldInfo[] fieldsArray = new FieldInfo[12];
|
||||
|
||||
static {
|
||||
int offset = 0;
|
||||
fieldsArray[FIELD_INDEX_GROUP_NAME] = new FieldInfo("groupName", offset, ProtoCommon.FDFS_GROUP_NAME_MAX_LEN + 1);
|
||||
offset += ProtoCommon.FDFS_GROUP_NAME_MAX_LEN + 1;
|
||||
|
||||
fieldsArray[FIELD_INDEX_TOTAL_MB] = new FieldInfo("totalMB", offset, ProtoCommon.FDFS_PROTO_PKG_LEN_SIZE);
|
||||
offset += ProtoCommon.FDFS_PROTO_PKG_LEN_SIZE;
|
||||
|
||||
fieldsArray[FIELD_INDEX_FREE_MB] = new FieldInfo("freeMB", offset, ProtoCommon.FDFS_PROTO_PKG_LEN_SIZE);
|
||||
offset += ProtoCommon.FDFS_PROTO_PKG_LEN_SIZE;
|
||||
|
||||
fieldsArray[FIELD_INDEX_TRUNK_FREE_MB] = new FieldInfo("trunkFreeMB", offset, ProtoCommon.FDFS_PROTO_PKG_LEN_SIZE);
|
||||
offset += ProtoCommon.FDFS_PROTO_PKG_LEN_SIZE;
|
||||
|
||||
fieldsArray[FIELD_INDEX_STORAGE_COUNT] = new FieldInfo("storageCount", offset, ProtoCommon.FDFS_PROTO_PKG_LEN_SIZE);
|
||||
offset += ProtoCommon.FDFS_PROTO_PKG_LEN_SIZE;
|
||||
|
||||
fieldsArray[FIELD_INDEX_STORAGE_PORT] = new FieldInfo("storagePort", offset, ProtoCommon.FDFS_PROTO_PKG_LEN_SIZE);
|
||||
offset += ProtoCommon.FDFS_PROTO_PKG_LEN_SIZE;
|
||||
|
||||
fieldsArray[FIELD_INDEX_STORAGE_HTTP_PORT] = new FieldInfo("storageHttpPort", offset, ProtoCommon.FDFS_PROTO_PKG_LEN_SIZE);
|
||||
offset += ProtoCommon.FDFS_PROTO_PKG_LEN_SIZE;
|
||||
|
||||
fieldsArray[FIELD_INDEX_ACTIVE_COUNT] = new FieldInfo("activeCount", offset, ProtoCommon.FDFS_PROTO_PKG_LEN_SIZE);
|
||||
offset += ProtoCommon.FDFS_PROTO_PKG_LEN_SIZE;
|
||||
|
||||
fieldsArray[FIELD_INDEX_CURRENT_WRITE_SERVER] = new FieldInfo("currentWriteServer", offset, ProtoCommon.FDFS_PROTO_PKG_LEN_SIZE);
|
||||
offset += ProtoCommon.FDFS_PROTO_PKG_LEN_SIZE;
|
||||
|
||||
fieldsArray[FIELD_INDEX_STORE_PATH_COUNT] = new FieldInfo("storePathCount", offset, ProtoCommon.FDFS_PROTO_PKG_LEN_SIZE);
|
||||
offset += ProtoCommon.FDFS_PROTO_PKG_LEN_SIZE;
|
||||
|
||||
fieldsArray[FIELD_INDEX_SUBDIR_COUNT_PER_PATH] = new FieldInfo("subdirCountPerPath", offset, ProtoCommon.FDFS_PROTO_PKG_LEN_SIZE);
|
||||
offset += ProtoCommon.FDFS_PROTO_PKG_LEN_SIZE;
|
||||
|
||||
fieldsArray[FIELD_INDEX_CURRENT_TRUNK_FILE_ID] = new FieldInfo("currentTrunkFileId", offset, ProtoCommon.FDFS_PROTO_PKG_LEN_SIZE);
|
||||
offset += ProtoCommon.FDFS_PROTO_PKG_LEN_SIZE;
|
||||
|
||||
fieldsTotalSize = offset;
|
||||
}
|
||||
|
||||
protected String groupName; //name of this group
|
||||
protected long totalMB; //total disk storage in MB
|
||||
protected long freeMB; //free disk space in MB
|
||||
protected long trunkFreeMB; //trunk free space in MB
|
||||
protected int storageCount; //storage server count
|
||||
protected int storagePort; //storage server port
|
||||
protected int storageHttpPort; //storage server HTTP port
|
||||
protected int activeCount; //active storage server count
|
||||
protected int currentWriteServer; //current storage server index to upload file
|
||||
protected int storePathCount; //store base path count of each storage server
|
||||
protected int subdirCountPerPath; //sub dir count per store path
|
||||
protected int currentTrunkFileId; //current trunk file id
|
||||
|
||||
/**
|
||||
* get fields total size
|
||||
*
|
||||
* @return fields total size
|
||||
*/
|
||||
public static int getFieldsTotalSize() {
|
||||
return fieldsTotalSize;
|
||||
}
|
||||
|
||||
/**
|
||||
* get group name
|
||||
*
|
||||
* @return group name
|
||||
*/
|
||||
public String getGroupName() {
|
||||
return this.groupName;
|
||||
}
|
||||
|
||||
/**
|
||||
* get total disk space in MB
|
||||
*
|
||||
* @return total disk space in MB
|
||||
*/
|
||||
public long getTotalMB() {
|
||||
return this.totalMB;
|
||||
}
|
||||
|
||||
/**
|
||||
* get free disk space in MB
|
||||
*
|
||||
* @return free disk space in MB
|
||||
*/
|
||||
public long getFreeMB() {
|
||||
return this.freeMB;
|
||||
}
|
||||
|
||||
/**
|
||||
* get trunk free space in MB
|
||||
*
|
||||
* @return trunk free space in MB
|
||||
*/
|
||||
public long getTrunkFreeMB() {
|
||||
return this.trunkFreeMB;
|
||||
}
|
||||
|
||||
/**
|
||||
* get storage server count in this group
|
||||
*
|
||||
* @return storage server count in this group
|
||||
*/
|
||||
public int getStorageCount() {
|
||||
return this.storageCount;
|
||||
}
|
||||
|
||||
/**
|
||||
* get active storage server count in this group
|
||||
*
|
||||
* @return active storage server count in this group
|
||||
*/
|
||||
public int getActiveCount() {
|
||||
return this.activeCount;
|
||||
}
|
||||
|
||||
/**
|
||||
* get storage server port
|
||||
*
|
||||
* @return storage server port
|
||||
*/
|
||||
public int getStoragePort() {
|
||||
return this.storagePort;
|
||||
}
|
||||
|
||||
/**
|
||||
* get storage server HTTP port
|
||||
*
|
||||
* @return storage server HTTP port
|
||||
*/
|
||||
public int getStorageHttpPort() {
|
||||
return this.storageHttpPort;
|
||||
}
|
||||
|
||||
/**
|
||||
* get current storage server index to upload file
|
||||
*
|
||||
* @return current storage server index to upload file
|
||||
*/
|
||||
public int getCurrentWriteServer() {
|
||||
return this.currentWriteServer;
|
||||
}
|
||||
|
||||
/**
|
||||
* get store base path count of each storage server
|
||||
*
|
||||
* @return store base path count of each storage server
|
||||
*/
|
||||
public int getStorePathCount() {
|
||||
return this.storePathCount;
|
||||
}
|
||||
|
||||
/**
|
||||
* get sub dir count per store path
|
||||
*
|
||||
* @return sub dir count per store path
|
||||
*/
|
||||
public int getSubdirCountPerPath() {
|
||||
return this.subdirCountPerPath;
|
||||
}
|
||||
|
||||
/**
|
||||
* get current trunk file id
|
||||
*
|
||||
* @return current trunk file id
|
||||
*/
|
||||
public int getCurrentTrunkFileId() {
|
||||
return this.currentTrunkFileId;
|
||||
}
|
||||
|
||||
/**
|
||||
* set fields
|
||||
*
|
||||
* @param bs byte array
|
||||
* @param offset start offset
|
||||
*/
|
||||
public void setFields(byte[] bs, int offset) {
|
||||
this.groupName = stringValue(bs, offset, fieldsArray[FIELD_INDEX_GROUP_NAME]);
|
||||
this.totalMB = longValue(bs, offset, fieldsArray[FIELD_INDEX_TOTAL_MB]);
|
||||
this.freeMB = longValue(bs, offset, fieldsArray[FIELD_INDEX_FREE_MB]);
|
||||
this.trunkFreeMB = longValue(bs, offset, fieldsArray[FIELD_INDEX_TRUNK_FREE_MB]);
|
||||
this.storageCount = intValue(bs, offset, fieldsArray[FIELD_INDEX_STORAGE_COUNT]);
|
||||
this.storagePort = intValue(bs, offset, fieldsArray[FIELD_INDEX_STORAGE_PORT]);
|
||||
this.storageHttpPort = intValue(bs, offset, fieldsArray[FIELD_INDEX_STORAGE_HTTP_PORT]);
|
||||
this.activeCount = intValue(bs, offset, fieldsArray[FIELD_INDEX_ACTIVE_COUNT]);
|
||||
this.currentWriteServer = intValue(bs, offset, fieldsArray[FIELD_INDEX_CURRENT_WRITE_SERVER]);
|
||||
this.storePathCount = intValue(bs, offset, fieldsArray[FIELD_INDEX_STORE_PATH_COUNT]);
|
||||
this.subdirCountPerPath = intValue(bs, offset, fieldsArray[FIELD_INDEX_SUBDIR_COUNT_PER_PATH]);
|
||||
this.currentTrunkFileId = intValue(bs, offset, fieldsArray[FIELD_INDEX_CURRENT_TRUNK_FILE_ID]);
|
||||
}
|
||||
}
|
||||
+982
@@ -0,0 +1,982 @@
|
||||
/**
|
||||
* Copyright (C) 2008 Happy Fish / YuQing
|
||||
* <p>
|
||||
* FastDFS Java Client may be copied only under the terms of the GNU Lesser
|
||||
* General Public License (LGPL).
|
||||
* Please visit the FastDFS Home Page https://github.com/happyfish100/fastdfs for more detail.
|
||||
*/
|
||||
|
||||
package com.csource.fastdfs;
|
||||
|
||||
import java.util.Date;
|
||||
|
||||
/**
|
||||
* C struct body decoder
|
||||
*
|
||||
* @author Happy Fish / YuQing
|
||||
* @version Version 1.25
|
||||
*/
|
||||
public class StructStorageStat extends StructBase {
|
||||
protected static final int FIELD_INDEX_STATUS = 0;
|
||||
protected static final int FIELD_INDEX_ID = 1;
|
||||
protected static final int FIELD_INDEX_IP_ADDR = 2;
|
||||
protected static final int FIELD_INDEX_DOMAIN_NAME = 3;
|
||||
protected static final int FIELD_INDEX_SRC_IP_ADDR = 4;
|
||||
protected static final int FIELD_INDEX_VERSION = 5;
|
||||
protected static final int FIELD_INDEX_JOIN_TIME = 6;
|
||||
protected static final int FIELD_INDEX_UP_TIME = 7;
|
||||
protected static final int FIELD_INDEX_TOTAL_MB = 8;
|
||||
protected static final int FIELD_INDEX_FREE_MB = 9;
|
||||
protected static final int FIELD_INDEX_UPLOAD_PRIORITY = 10;
|
||||
protected static final int FIELD_INDEX_STORE_PATH_COUNT = 11;
|
||||
protected static final int FIELD_INDEX_SUBDIR_COUNT_PER_PATH = 12;
|
||||
protected static final int FIELD_INDEX_CURRENT_WRITE_PATH = 13;
|
||||
protected static final int FIELD_INDEX_STORAGE_PORT = 14;
|
||||
protected static final int FIELD_INDEX_STORAGE_HTTP_PORT = 15;
|
||||
|
||||
protected static final int FIELD_INDEX_CONNECTION_ALLOC_COUNT = 16;
|
||||
protected static final int FIELD_INDEX_CONNECTION_CURRENT_COUNT = 17;
|
||||
protected static final int FIELD_INDEX_CONNECTION_MAX_COUNT = 18;
|
||||
|
||||
protected static final int FIELD_INDEX_TOTAL_UPLOAD_COUNT = 19;
|
||||
protected static final int FIELD_INDEX_SUCCESS_UPLOAD_COUNT = 20;
|
||||
protected static final int FIELD_INDEX_TOTAL_APPEND_COUNT = 21;
|
||||
protected static final int FIELD_INDEX_SUCCESS_APPEND_COUNT = 22;
|
||||
protected static final int FIELD_INDEX_TOTAL_MODIFY_COUNT = 23;
|
||||
protected static final int FIELD_INDEX_SUCCESS_MODIFY_COUNT = 24;
|
||||
protected static final int FIELD_INDEX_TOTAL_TRUNCATE_COUNT = 25;
|
||||
protected static final int FIELD_INDEX_SUCCESS_TRUNCATE_COUNT = 26;
|
||||
protected static final int FIELD_INDEX_TOTAL_SET_META_COUNT = 27;
|
||||
protected static final int FIELD_INDEX_SUCCESS_SET_META_COUNT = 28;
|
||||
protected static final int FIELD_INDEX_TOTAL_DELETE_COUNT = 29;
|
||||
protected static final int FIELD_INDEX_SUCCESS_DELETE_COUNT = 30;
|
||||
protected static final int FIELD_INDEX_TOTAL_DOWNLOAD_COUNT = 31;
|
||||
protected static final int FIELD_INDEX_SUCCESS_DOWNLOAD_COUNT = 32;
|
||||
protected static final int FIELD_INDEX_TOTAL_GET_META_COUNT = 33;
|
||||
protected static final int FIELD_INDEX_SUCCESS_GET_META_COUNT = 34;
|
||||
protected static final int FIELD_INDEX_TOTAL_CREATE_LINK_COUNT = 35;
|
||||
protected static final int FIELD_INDEX_SUCCESS_CREATE_LINK_COUNT = 36;
|
||||
protected static final int FIELD_INDEX_TOTAL_DELETE_LINK_COUNT = 37;
|
||||
protected static final int FIELD_INDEX_SUCCESS_DELETE_LINK_COUNT = 38;
|
||||
protected static final int FIELD_INDEX_TOTAL_UPLOAD_BYTES = 39;
|
||||
protected static final int FIELD_INDEX_SUCCESS_UPLOAD_BYTES = 40;
|
||||
protected static final int FIELD_INDEX_TOTAL_APPEND_BYTES = 41;
|
||||
protected static final int FIELD_INDEX_SUCCESS_APPEND_BYTES = 42;
|
||||
protected static final int FIELD_INDEX_TOTAL_MODIFY_BYTES = 43;
|
||||
protected static final int FIELD_INDEX_SUCCESS_MODIFY_BYTES = 44;
|
||||
protected static final int FIELD_INDEX_TOTAL_DOWNLOAD_BYTES = 45;
|
||||
protected static final int FIELD_INDEX_SUCCESS_DOWNLOAD_BYTES = 46;
|
||||
protected static final int FIELD_INDEX_TOTAL_SYNC_IN_BYTES = 47;
|
||||
protected static final int FIELD_INDEX_SUCCESS_SYNC_IN_BYTES = 48;
|
||||
protected static final int FIELD_INDEX_TOTAL_SYNC_OUT_BYTES = 49;
|
||||
protected static final int FIELD_INDEX_SUCCESS_SYNC_OUT_BYTES = 50;
|
||||
protected static final int FIELD_INDEX_TOTAL_FILE_OPEN_COUNT = 51;
|
||||
protected static final int FIELD_INDEX_SUCCESS_FILE_OPEN_COUNT = 52;
|
||||
protected static final int FIELD_INDEX_TOTAL_FILE_READ_COUNT = 53;
|
||||
protected static final int FIELD_INDEX_SUCCESS_FILE_READ_COUNT = 54;
|
||||
protected static final int FIELD_INDEX_TOTAL_FILE_WRITE_COUNT = 55;
|
||||
protected static final int FIELD_INDEX_SUCCESS_FILE_WRITE_COUNT = 56;
|
||||
protected static final int FIELD_INDEX_LAST_SOURCE_UPDATE = 57;
|
||||
protected static final int FIELD_INDEX_LAST_SYNC_UPDATE = 58;
|
||||
protected static final int FIELD_INDEX_LAST_SYNCED_TIMESTAMP = 59;
|
||||
protected static final int FIELD_INDEX_LAST_HEART_BEAT_TIME = 60;
|
||||
protected static final int FIELD_INDEX_IF_TRUNK_FILE = 61;
|
||||
|
||||
protected static int fieldsTotalSize;
|
||||
protected static FieldInfo[] fieldsArray = new FieldInfo[62];
|
||||
|
||||
static {
|
||||
int offset = 0;
|
||||
|
||||
fieldsArray[FIELD_INDEX_STATUS] = new FieldInfo("status", offset, 1);
|
||||
offset += 1;
|
||||
|
||||
fieldsArray[FIELD_INDEX_ID] = new FieldInfo("id", offset, ProtoCommon.FDFS_STORAGE_ID_MAX_SIZE);
|
||||
offset += ProtoCommon.FDFS_STORAGE_ID_MAX_SIZE;
|
||||
|
||||
fieldsArray[FIELD_INDEX_IP_ADDR] = new FieldInfo("ipAddr", offset, ProtoCommon.FDFS_IPADDR_SIZE);
|
||||
offset += ProtoCommon.FDFS_IPADDR_SIZE;
|
||||
|
||||
fieldsArray[FIELD_INDEX_DOMAIN_NAME] = new FieldInfo("domainName", offset, ProtoCommon.FDFS_DOMAIN_NAME_MAX_SIZE);
|
||||
offset += ProtoCommon.FDFS_DOMAIN_NAME_MAX_SIZE;
|
||||
|
||||
fieldsArray[FIELD_INDEX_SRC_IP_ADDR] = new FieldInfo("srcIpAddr", offset, ProtoCommon.FDFS_IPADDR_SIZE);
|
||||
offset += ProtoCommon.FDFS_IPADDR_SIZE;
|
||||
|
||||
fieldsArray[FIELD_INDEX_VERSION] = new FieldInfo("version", offset, ProtoCommon.FDFS_VERSION_SIZE);
|
||||
offset += ProtoCommon.FDFS_VERSION_SIZE;
|
||||
|
||||
fieldsArray[FIELD_INDEX_JOIN_TIME] = new FieldInfo("joinTime", offset, ProtoCommon.FDFS_PROTO_PKG_LEN_SIZE);
|
||||
offset += ProtoCommon.FDFS_PROTO_PKG_LEN_SIZE;
|
||||
|
||||
fieldsArray[FIELD_INDEX_UP_TIME] = new FieldInfo("upTime", offset, ProtoCommon.FDFS_PROTO_PKG_LEN_SIZE);
|
||||
offset += ProtoCommon.FDFS_PROTO_PKG_LEN_SIZE;
|
||||
|
||||
fieldsArray[FIELD_INDEX_TOTAL_MB] = new FieldInfo("totalMB", offset, ProtoCommon.FDFS_PROTO_PKG_LEN_SIZE);
|
||||
offset += ProtoCommon.FDFS_PROTO_PKG_LEN_SIZE;
|
||||
|
||||
fieldsArray[FIELD_INDEX_FREE_MB] = new FieldInfo("freeMB", offset, ProtoCommon.FDFS_PROTO_PKG_LEN_SIZE);
|
||||
offset += ProtoCommon.FDFS_PROTO_PKG_LEN_SIZE;
|
||||
|
||||
fieldsArray[FIELD_INDEX_UPLOAD_PRIORITY] = new FieldInfo("uploadPriority", offset, ProtoCommon.FDFS_PROTO_PKG_LEN_SIZE);
|
||||
offset += ProtoCommon.FDFS_PROTO_PKG_LEN_SIZE;
|
||||
|
||||
fieldsArray[FIELD_INDEX_STORE_PATH_COUNT] = new FieldInfo("storePathCount", offset, ProtoCommon.FDFS_PROTO_PKG_LEN_SIZE);
|
||||
offset += ProtoCommon.FDFS_PROTO_PKG_LEN_SIZE;
|
||||
|
||||
fieldsArray[FIELD_INDEX_SUBDIR_COUNT_PER_PATH] = new FieldInfo("subdirCountPerPath", offset, ProtoCommon.FDFS_PROTO_PKG_LEN_SIZE);
|
||||
offset += ProtoCommon.FDFS_PROTO_PKG_LEN_SIZE;
|
||||
|
||||
fieldsArray[FIELD_INDEX_CURRENT_WRITE_PATH] = new FieldInfo("currentWritePath", offset, ProtoCommon.FDFS_PROTO_PKG_LEN_SIZE);
|
||||
offset += ProtoCommon.FDFS_PROTO_PKG_LEN_SIZE;
|
||||
|
||||
fieldsArray[FIELD_INDEX_STORAGE_PORT] = new FieldInfo("storagePort", offset, ProtoCommon.FDFS_PROTO_PKG_LEN_SIZE);
|
||||
offset += ProtoCommon.FDFS_PROTO_PKG_LEN_SIZE;
|
||||
|
||||
fieldsArray[FIELD_INDEX_STORAGE_HTTP_PORT] = new FieldInfo("storageHttpPort", offset, ProtoCommon.FDFS_PROTO_PKG_LEN_SIZE);
|
||||
offset += ProtoCommon.FDFS_PROTO_PKG_LEN_SIZE;
|
||||
|
||||
fieldsArray[FIELD_INDEX_CONNECTION_ALLOC_COUNT] = new FieldInfo("connectionAllocCount", offset, 4);
|
||||
offset += 4;
|
||||
|
||||
fieldsArray[FIELD_INDEX_CONNECTION_CURRENT_COUNT] = new FieldInfo("connectionCurrentCount", offset, 4);
|
||||
offset += 4;
|
||||
|
||||
fieldsArray[FIELD_INDEX_CONNECTION_MAX_COUNT] = new FieldInfo("connectionMaxCount", offset, 4);
|
||||
offset += 4;
|
||||
|
||||
fieldsArray[FIELD_INDEX_TOTAL_UPLOAD_COUNT] = new FieldInfo("totalUploadCount", offset, ProtoCommon.FDFS_PROTO_PKG_LEN_SIZE);
|
||||
offset += ProtoCommon.FDFS_PROTO_PKG_LEN_SIZE;
|
||||
|
||||
fieldsArray[FIELD_INDEX_SUCCESS_UPLOAD_COUNT] = new FieldInfo("successUploadCount", offset, ProtoCommon.FDFS_PROTO_PKG_LEN_SIZE);
|
||||
offset += ProtoCommon.FDFS_PROTO_PKG_LEN_SIZE;
|
||||
|
||||
fieldsArray[FIELD_INDEX_TOTAL_APPEND_COUNT] = new FieldInfo("totalAppendCount", offset, ProtoCommon.FDFS_PROTO_PKG_LEN_SIZE);
|
||||
offset += ProtoCommon.FDFS_PROTO_PKG_LEN_SIZE;
|
||||
|
||||
fieldsArray[FIELD_INDEX_SUCCESS_APPEND_COUNT] = new FieldInfo("successAppendCount", offset, ProtoCommon.FDFS_PROTO_PKG_LEN_SIZE);
|
||||
offset += ProtoCommon.FDFS_PROTO_PKG_LEN_SIZE;
|
||||
|
||||
fieldsArray[FIELD_INDEX_TOTAL_MODIFY_COUNT] = new FieldInfo("totalModifyCount", offset, ProtoCommon.FDFS_PROTO_PKG_LEN_SIZE);
|
||||
offset += ProtoCommon.FDFS_PROTO_PKG_LEN_SIZE;
|
||||
|
||||
fieldsArray[FIELD_INDEX_SUCCESS_MODIFY_COUNT] = new FieldInfo("successModifyCount", offset, ProtoCommon.FDFS_PROTO_PKG_LEN_SIZE);
|
||||
offset += ProtoCommon.FDFS_PROTO_PKG_LEN_SIZE;
|
||||
|
||||
fieldsArray[FIELD_INDEX_TOTAL_TRUNCATE_COUNT] = new FieldInfo("totalTruncateCount", offset, ProtoCommon.FDFS_PROTO_PKG_LEN_SIZE);
|
||||
offset += ProtoCommon.FDFS_PROTO_PKG_LEN_SIZE;
|
||||
|
||||
fieldsArray[FIELD_INDEX_SUCCESS_TRUNCATE_COUNT] = new FieldInfo("successTruncateCount", offset, ProtoCommon.FDFS_PROTO_PKG_LEN_SIZE);
|
||||
offset += ProtoCommon.FDFS_PROTO_PKG_LEN_SIZE;
|
||||
|
||||
fieldsArray[FIELD_INDEX_TOTAL_SET_META_COUNT] = new FieldInfo("totalSetMetaCount", offset, ProtoCommon.FDFS_PROTO_PKG_LEN_SIZE);
|
||||
offset += ProtoCommon.FDFS_PROTO_PKG_LEN_SIZE;
|
||||
|
||||
fieldsArray[FIELD_INDEX_SUCCESS_SET_META_COUNT] = new FieldInfo("successSetMetaCount", offset, ProtoCommon.FDFS_PROTO_PKG_LEN_SIZE);
|
||||
offset += ProtoCommon.FDFS_PROTO_PKG_LEN_SIZE;
|
||||
|
||||
fieldsArray[FIELD_INDEX_TOTAL_DELETE_COUNT] = new FieldInfo("totalDeleteCount", offset, ProtoCommon.FDFS_PROTO_PKG_LEN_SIZE);
|
||||
offset += ProtoCommon.FDFS_PROTO_PKG_LEN_SIZE;
|
||||
|
||||
fieldsArray[FIELD_INDEX_SUCCESS_DELETE_COUNT] = new FieldInfo("successDeleteCount", offset, ProtoCommon.FDFS_PROTO_PKG_LEN_SIZE);
|
||||
offset += ProtoCommon.FDFS_PROTO_PKG_LEN_SIZE;
|
||||
|
||||
fieldsArray[FIELD_INDEX_TOTAL_DOWNLOAD_COUNT] = new FieldInfo("totalDownloadCount", offset, ProtoCommon.FDFS_PROTO_PKG_LEN_SIZE);
|
||||
offset += ProtoCommon.FDFS_PROTO_PKG_LEN_SIZE;
|
||||
|
||||
fieldsArray[FIELD_INDEX_SUCCESS_DOWNLOAD_COUNT] = new FieldInfo("successDownloadCount", offset, ProtoCommon.FDFS_PROTO_PKG_LEN_SIZE);
|
||||
offset += ProtoCommon.FDFS_PROTO_PKG_LEN_SIZE;
|
||||
|
||||
fieldsArray[FIELD_INDEX_TOTAL_GET_META_COUNT] = new FieldInfo("totalGetMetaCount", offset, ProtoCommon.FDFS_PROTO_PKG_LEN_SIZE);
|
||||
offset += ProtoCommon.FDFS_PROTO_PKG_LEN_SIZE;
|
||||
|
||||
fieldsArray[FIELD_INDEX_SUCCESS_GET_META_COUNT] = new FieldInfo("successGetMetaCount", offset, ProtoCommon.FDFS_PROTO_PKG_LEN_SIZE);
|
||||
offset += ProtoCommon.FDFS_PROTO_PKG_LEN_SIZE;
|
||||
|
||||
fieldsArray[FIELD_INDEX_TOTAL_CREATE_LINK_COUNT] = new FieldInfo("totalCreateLinkCount", offset, ProtoCommon.FDFS_PROTO_PKG_LEN_SIZE);
|
||||
offset += ProtoCommon.FDFS_PROTO_PKG_LEN_SIZE;
|
||||
|
||||
fieldsArray[FIELD_INDEX_SUCCESS_CREATE_LINK_COUNT] = new FieldInfo("successCreateLinkCount", offset, ProtoCommon.FDFS_PROTO_PKG_LEN_SIZE);
|
||||
offset += ProtoCommon.FDFS_PROTO_PKG_LEN_SIZE;
|
||||
|
||||
fieldsArray[FIELD_INDEX_TOTAL_DELETE_LINK_COUNT] = new FieldInfo("totalDeleteLinkCount", offset, ProtoCommon.FDFS_PROTO_PKG_LEN_SIZE);
|
||||
offset += ProtoCommon.FDFS_PROTO_PKG_LEN_SIZE;
|
||||
|
||||
fieldsArray[FIELD_INDEX_SUCCESS_DELETE_LINK_COUNT] = new FieldInfo("successDeleteLinkCount", offset, ProtoCommon.FDFS_PROTO_PKG_LEN_SIZE);
|
||||
offset += ProtoCommon.FDFS_PROTO_PKG_LEN_SIZE;
|
||||
|
||||
fieldsArray[FIELD_INDEX_TOTAL_UPLOAD_BYTES] = new FieldInfo("totalUploadBytes", offset, ProtoCommon.FDFS_PROTO_PKG_LEN_SIZE);
|
||||
offset += ProtoCommon.FDFS_PROTO_PKG_LEN_SIZE;
|
||||
|
||||
fieldsArray[FIELD_INDEX_SUCCESS_UPLOAD_BYTES] = new FieldInfo("successUploadBytes", offset, ProtoCommon.FDFS_PROTO_PKG_LEN_SIZE);
|
||||
offset += ProtoCommon.FDFS_PROTO_PKG_LEN_SIZE;
|
||||
|
||||
fieldsArray[FIELD_INDEX_TOTAL_APPEND_BYTES] = new FieldInfo("totalAppendBytes", offset, ProtoCommon.FDFS_PROTO_PKG_LEN_SIZE);
|
||||
offset += ProtoCommon.FDFS_PROTO_PKG_LEN_SIZE;
|
||||
|
||||
fieldsArray[FIELD_INDEX_SUCCESS_APPEND_BYTES] = new FieldInfo("successAppendBytes", offset, ProtoCommon.FDFS_PROTO_PKG_LEN_SIZE);
|
||||
offset += ProtoCommon.FDFS_PROTO_PKG_LEN_SIZE;
|
||||
|
||||
fieldsArray[FIELD_INDEX_TOTAL_MODIFY_BYTES] = new FieldInfo("totalModifyBytes", offset, ProtoCommon.FDFS_PROTO_PKG_LEN_SIZE);
|
||||
offset += ProtoCommon.FDFS_PROTO_PKG_LEN_SIZE;
|
||||
|
||||
fieldsArray[FIELD_INDEX_SUCCESS_MODIFY_BYTES] = new FieldInfo("successModifyBytes", offset, ProtoCommon.FDFS_PROTO_PKG_LEN_SIZE);
|
||||
offset += ProtoCommon.FDFS_PROTO_PKG_LEN_SIZE;
|
||||
|
||||
fieldsArray[FIELD_INDEX_TOTAL_DOWNLOAD_BYTES] = new FieldInfo("totalDownloadloadBytes", offset, ProtoCommon.FDFS_PROTO_PKG_LEN_SIZE);
|
||||
offset += ProtoCommon.FDFS_PROTO_PKG_LEN_SIZE;
|
||||
|
||||
fieldsArray[FIELD_INDEX_SUCCESS_DOWNLOAD_BYTES] = new FieldInfo("successDownloadloadBytes", offset, ProtoCommon.FDFS_PROTO_PKG_LEN_SIZE);
|
||||
offset += ProtoCommon.FDFS_PROTO_PKG_LEN_SIZE;
|
||||
|
||||
fieldsArray[FIELD_INDEX_TOTAL_SYNC_IN_BYTES] = new FieldInfo("totalSyncInBytes", offset, ProtoCommon.FDFS_PROTO_PKG_LEN_SIZE);
|
||||
offset += ProtoCommon.FDFS_PROTO_PKG_LEN_SIZE;
|
||||
|
||||
fieldsArray[FIELD_INDEX_SUCCESS_SYNC_IN_BYTES] = new FieldInfo("successSyncInBytes", offset, ProtoCommon.FDFS_PROTO_PKG_LEN_SIZE);
|
||||
offset += ProtoCommon.FDFS_PROTO_PKG_LEN_SIZE;
|
||||
|
||||
fieldsArray[FIELD_INDEX_TOTAL_SYNC_OUT_BYTES] = new FieldInfo("totalSyncOutBytes", offset, ProtoCommon.FDFS_PROTO_PKG_LEN_SIZE);
|
||||
offset += ProtoCommon.FDFS_PROTO_PKG_LEN_SIZE;
|
||||
|
||||
fieldsArray[FIELD_INDEX_SUCCESS_SYNC_OUT_BYTES] = new FieldInfo("successSyncOutBytes", offset, ProtoCommon.FDFS_PROTO_PKG_LEN_SIZE);
|
||||
offset += ProtoCommon.FDFS_PROTO_PKG_LEN_SIZE;
|
||||
|
||||
fieldsArray[FIELD_INDEX_TOTAL_FILE_OPEN_COUNT] = new FieldInfo("totalFileOpenCount", offset, ProtoCommon.FDFS_PROTO_PKG_LEN_SIZE);
|
||||
offset += ProtoCommon.FDFS_PROTO_PKG_LEN_SIZE;
|
||||
|
||||
fieldsArray[FIELD_INDEX_SUCCESS_FILE_OPEN_COUNT] = new FieldInfo("successFileOpenCount", offset, ProtoCommon.FDFS_PROTO_PKG_LEN_SIZE);
|
||||
offset += ProtoCommon.FDFS_PROTO_PKG_LEN_SIZE;
|
||||
|
||||
fieldsArray[FIELD_INDEX_TOTAL_FILE_READ_COUNT] = new FieldInfo("totalFileReadCount", offset, ProtoCommon.FDFS_PROTO_PKG_LEN_SIZE);
|
||||
offset += ProtoCommon.FDFS_PROTO_PKG_LEN_SIZE;
|
||||
|
||||
fieldsArray[FIELD_INDEX_SUCCESS_FILE_READ_COUNT] = new FieldInfo("successFileReadCount", offset, ProtoCommon.FDFS_PROTO_PKG_LEN_SIZE);
|
||||
offset += ProtoCommon.FDFS_PROTO_PKG_LEN_SIZE;
|
||||
|
||||
fieldsArray[FIELD_INDEX_TOTAL_FILE_WRITE_COUNT] = new FieldInfo("totalFileWriteCount", offset, ProtoCommon.FDFS_PROTO_PKG_LEN_SIZE);
|
||||
offset += ProtoCommon.FDFS_PROTO_PKG_LEN_SIZE;
|
||||
|
||||
fieldsArray[FIELD_INDEX_SUCCESS_FILE_WRITE_COUNT] = new FieldInfo("successFileWriteCount", offset, ProtoCommon.FDFS_PROTO_PKG_LEN_SIZE);
|
||||
offset += ProtoCommon.FDFS_PROTO_PKG_LEN_SIZE;
|
||||
|
||||
fieldsArray[FIELD_INDEX_LAST_SOURCE_UPDATE] = new FieldInfo("lastSourceUpdate", offset, ProtoCommon.FDFS_PROTO_PKG_LEN_SIZE);
|
||||
offset += ProtoCommon.FDFS_PROTO_PKG_LEN_SIZE;
|
||||
|
||||
fieldsArray[FIELD_INDEX_LAST_SYNC_UPDATE] = new FieldInfo("lastSyncUpdate", offset, ProtoCommon.FDFS_PROTO_PKG_LEN_SIZE);
|
||||
offset += ProtoCommon.FDFS_PROTO_PKG_LEN_SIZE;
|
||||
|
||||
fieldsArray[FIELD_INDEX_LAST_SYNCED_TIMESTAMP] = new FieldInfo("lastSyncedTimestamp", offset, ProtoCommon.FDFS_PROTO_PKG_LEN_SIZE);
|
||||
offset += ProtoCommon.FDFS_PROTO_PKG_LEN_SIZE;
|
||||
|
||||
fieldsArray[FIELD_INDEX_LAST_HEART_BEAT_TIME] = new FieldInfo("lastHeartBeatTime", offset, ProtoCommon.FDFS_PROTO_PKG_LEN_SIZE);
|
||||
offset += ProtoCommon.FDFS_PROTO_PKG_LEN_SIZE;
|
||||
|
||||
fieldsArray[FIELD_INDEX_IF_TRUNK_FILE] = new FieldInfo("ifTrunkServer", offset, 1);
|
||||
offset += 1;
|
||||
|
||||
fieldsTotalSize = offset;
|
||||
}
|
||||
|
||||
protected byte status;
|
||||
protected String id;
|
||||
protected String ipAddr;
|
||||
protected String srcIpAddr;
|
||||
protected String domainName; //http domain name
|
||||
protected String version;
|
||||
protected long totalMB; //total disk storage in MB
|
||||
protected long freeMB; //free disk storage in MB
|
||||
protected int uploadPriority; //upload priority
|
||||
protected Date joinTime; //storage join timestamp (create timestamp)
|
||||
protected Date upTime; //storage service started timestamp
|
||||
protected int storePathCount; //store base path count of each storage server
|
||||
protected int subdirCountPerPath;
|
||||
protected int storagePort;
|
||||
protected int storageHttpPort; //storage http server port
|
||||
protected int currentWritePath; //current write path index
|
||||
protected int connectionAllocCount;
|
||||
protected int connectionCurrentCount;
|
||||
protected int connectionMaxCount;
|
||||
protected long totalUploadCount;
|
||||
protected long successUploadCount;
|
||||
protected long totalAppendCount;
|
||||
protected long successAppendCount;
|
||||
protected long totalModifyCount;
|
||||
protected long successModifyCount;
|
||||
protected long totalTruncateCount;
|
||||
protected long successTruncateCount;
|
||||
protected long totalSetMetaCount;
|
||||
protected long successSetMetaCount;
|
||||
protected long totalDeleteCount;
|
||||
protected long successDeleteCount;
|
||||
protected long totalDownloadCount;
|
||||
protected long successDownloadCount;
|
||||
protected long totalGetMetaCount;
|
||||
protected long successGetMetaCount;
|
||||
protected long totalCreateLinkCount;
|
||||
protected long successCreateLinkCount;
|
||||
protected long totalDeleteLinkCount;
|
||||
protected long successDeleteLinkCount;
|
||||
protected long totalUploadBytes;
|
||||
protected long successUploadBytes;
|
||||
protected long totalAppendBytes;
|
||||
protected long successAppendBytes;
|
||||
protected long totalModifyBytes;
|
||||
protected long successModifyBytes;
|
||||
protected long totalDownloadloadBytes;
|
||||
protected long successDownloadloadBytes;
|
||||
protected long totalSyncInBytes;
|
||||
protected long successSyncInBytes;
|
||||
protected long totalSyncOutBytes;
|
||||
protected long successSyncOutBytes;
|
||||
protected long totalFileOpenCount;
|
||||
protected long successFileOpenCount;
|
||||
protected long totalFileReadCount;
|
||||
protected long successFileReadCount;
|
||||
protected long totalFileWriteCount;
|
||||
protected long successFileWriteCount;
|
||||
protected Date lastSourceUpdate;
|
||||
protected Date lastSyncUpdate;
|
||||
protected Date lastSyncedTimestamp;
|
||||
protected Date lastHeartBeatTime;
|
||||
protected boolean ifTrunkServer;
|
||||
|
||||
/**
|
||||
* get fields total size
|
||||
*
|
||||
* @return fields total size
|
||||
*/
|
||||
public static int getFieldsTotalSize() {
|
||||
return fieldsTotalSize;
|
||||
}
|
||||
|
||||
/**
|
||||
* get storage status
|
||||
*
|
||||
* @return storage status
|
||||
*/
|
||||
public byte getStatus() {
|
||||
return this.status;
|
||||
}
|
||||
|
||||
/**
|
||||
* get storage server id
|
||||
*
|
||||
* @return storage server id
|
||||
*/
|
||||
public String getId() {
|
||||
return this.id;
|
||||
}
|
||||
|
||||
/**
|
||||
* get storage server ip address
|
||||
*
|
||||
* @return storage server ip address
|
||||
*/
|
||||
public String getIpAddr() {
|
||||
return this.ipAddr;
|
||||
}
|
||||
|
||||
/**
|
||||
* get source storage ip address
|
||||
*
|
||||
* @return source storage ip address
|
||||
*/
|
||||
public String getSrcIpAddr() {
|
||||
return this.srcIpAddr;
|
||||
}
|
||||
|
||||
/**
|
||||
* get the domain name of the storage server
|
||||
*
|
||||
* @return the domain name of the storage server
|
||||
*/
|
||||
public String getDomainName() {
|
||||
return this.domainName;
|
||||
}
|
||||
|
||||
/**
|
||||
* get storage version
|
||||
*
|
||||
* @return storage version
|
||||
*/
|
||||
public String getVersion() {
|
||||
return this.version;
|
||||
}
|
||||
|
||||
/**
|
||||
* get total disk space in MB
|
||||
*
|
||||
* @return total disk space in MB
|
||||
*/
|
||||
public long getTotalMB() {
|
||||
return this.totalMB;
|
||||
}
|
||||
|
||||
/**
|
||||
* get free disk space in MB
|
||||
*
|
||||
* @return free disk space in MB
|
||||
*/
|
||||
public long getFreeMB() {
|
||||
return this.freeMB;
|
||||
}
|
||||
|
||||
/**
|
||||
* get storage server upload priority
|
||||
*
|
||||
* @return storage server upload priority
|
||||
*/
|
||||
public int getUploadPriority() {
|
||||
return this.uploadPriority;
|
||||
}
|
||||
|
||||
/**
|
||||
* get storage server join time
|
||||
*
|
||||
* @return storage server join time
|
||||
*/
|
||||
public Date getJoinTime() {
|
||||
return this.joinTime;
|
||||
}
|
||||
|
||||
/**
|
||||
* get storage server up time
|
||||
*
|
||||
* @return storage server up time
|
||||
*/
|
||||
public Date getUpTime() {
|
||||
return this.upTime;
|
||||
}
|
||||
|
||||
/**
|
||||
* get store base path count of each storage server
|
||||
*
|
||||
* @return store base path count of each storage server
|
||||
*/
|
||||
public int getStorePathCount() {
|
||||
return this.storePathCount;
|
||||
}
|
||||
|
||||
/**
|
||||
* get sub dir count per store path
|
||||
*
|
||||
* @return sub dir count per store path
|
||||
*/
|
||||
public int getSubdirCountPerPath() {
|
||||
return this.subdirCountPerPath;
|
||||
}
|
||||
|
||||
/**
|
||||
* get storage server port
|
||||
*
|
||||
* @return storage server port
|
||||
*/
|
||||
public int getStoragePort() {
|
||||
return this.storagePort;
|
||||
}
|
||||
|
||||
/**
|
||||
* get storage server HTTP port
|
||||
*
|
||||
* @return storage server HTTP port
|
||||
*/
|
||||
public int getStorageHttpPort() {
|
||||
return this.storageHttpPort;
|
||||
}
|
||||
|
||||
/**
|
||||
* get current write path index
|
||||
*
|
||||
* @return current write path index
|
||||
*/
|
||||
public int getCurrentWritePath() {
|
||||
return this.currentWritePath;
|
||||
}
|
||||
|
||||
/**
|
||||
* get total upload file count
|
||||
*
|
||||
* @return total upload file count
|
||||
*/
|
||||
public long getTotalUploadCount() {
|
||||
return this.totalUploadCount;
|
||||
}
|
||||
|
||||
/**
|
||||
* get success upload file count
|
||||
*
|
||||
* @return success upload file count
|
||||
*/
|
||||
public long getSuccessUploadCount() {
|
||||
return this.successUploadCount;
|
||||
}
|
||||
|
||||
/**
|
||||
* get total append count
|
||||
*
|
||||
* @return total append count
|
||||
*/
|
||||
public long getTotalAppendCount() {
|
||||
return this.totalAppendCount;
|
||||
}
|
||||
|
||||
/**
|
||||
* get success append count
|
||||
*
|
||||
* @return success append count
|
||||
*/
|
||||
public long getSuccessAppendCount() {
|
||||
return this.successAppendCount;
|
||||
}
|
||||
|
||||
/**
|
||||
* get total modify count
|
||||
*
|
||||
* @return total modify count
|
||||
*/
|
||||
public long getTotalModifyCount() {
|
||||
return this.totalModifyCount;
|
||||
}
|
||||
|
||||
/**
|
||||
* get success modify count
|
||||
*
|
||||
* @return success modify count
|
||||
*/
|
||||
public long getSuccessModifyCount() {
|
||||
return this.successModifyCount;
|
||||
}
|
||||
|
||||
/**
|
||||
* get total truncate count
|
||||
*
|
||||
* @return total truncate count
|
||||
*/
|
||||
public long getTotalTruncateCount() {
|
||||
return this.totalTruncateCount;
|
||||
}
|
||||
|
||||
/**
|
||||
* get success truncate count
|
||||
*
|
||||
* @return success truncate count
|
||||
*/
|
||||
public long getSuccessTruncateCount() {
|
||||
return this.successTruncateCount;
|
||||
}
|
||||
|
||||
/**
|
||||
* get total set meta data count
|
||||
*
|
||||
* @return total set meta data count
|
||||
*/
|
||||
public long getTotalSetMetaCount() {
|
||||
return this.totalSetMetaCount;
|
||||
}
|
||||
|
||||
/**
|
||||
* get success set meta data count
|
||||
*
|
||||
* @return success set meta data count
|
||||
*/
|
||||
public long getSuccessSetMetaCount() {
|
||||
return this.successSetMetaCount;
|
||||
}
|
||||
|
||||
/**
|
||||
* get total delete file count
|
||||
*
|
||||
* @return total delete file count
|
||||
*/
|
||||
public long getTotalDeleteCount() {
|
||||
return this.totalDeleteCount;
|
||||
}
|
||||
|
||||
/**
|
||||
* get success delete file count
|
||||
*
|
||||
* @return success delete file count
|
||||
*/
|
||||
public long getSuccessDeleteCount() {
|
||||
return this.successDeleteCount;
|
||||
}
|
||||
|
||||
/**
|
||||
* get total download file count
|
||||
*
|
||||
* @return total download file count
|
||||
*/
|
||||
public long getTotalDownloadCount() {
|
||||
return this.totalDownloadCount;
|
||||
}
|
||||
|
||||
/**
|
||||
* get success download file count
|
||||
*
|
||||
* @return success download file count
|
||||
*/
|
||||
public long getSuccessDownloadCount() {
|
||||
return this.successDownloadCount;
|
||||
}
|
||||
|
||||
/**
|
||||
* get total get metadata count
|
||||
*
|
||||
* @return total get metadata count
|
||||
*/
|
||||
public long getTotalGetMetaCount() {
|
||||
return this.totalGetMetaCount;
|
||||
}
|
||||
|
||||
/**
|
||||
* get success get metadata count
|
||||
*
|
||||
* @return success get metadata count
|
||||
*/
|
||||
public long getSuccessGetMetaCount() {
|
||||
return this.successGetMetaCount;
|
||||
}
|
||||
|
||||
/**
|
||||
* get total create linke count
|
||||
*
|
||||
* @return total create linke count
|
||||
*/
|
||||
public long getTotalCreateLinkCount() {
|
||||
return this.totalCreateLinkCount;
|
||||
}
|
||||
|
||||
/**
|
||||
* get success create linke count
|
||||
*
|
||||
* @return success create linke count
|
||||
*/
|
||||
public long getSuccessCreateLinkCount() {
|
||||
return this.successCreateLinkCount;
|
||||
}
|
||||
|
||||
/**
|
||||
* get total delete link count
|
||||
*
|
||||
* @return total delete link count
|
||||
*/
|
||||
public long getTotalDeleteLinkCount() {
|
||||
return this.totalDeleteLinkCount;
|
||||
}
|
||||
|
||||
/**
|
||||
* get success delete link count
|
||||
*
|
||||
* @return success delete link count
|
||||
*/
|
||||
public long getSuccessDeleteLinkCount() {
|
||||
return this.successDeleteLinkCount;
|
||||
}
|
||||
|
||||
/**
|
||||
* get total upload file bytes
|
||||
*
|
||||
* @return total upload file bytes
|
||||
*/
|
||||
public long getTotalUploadBytes() {
|
||||
return this.totalUploadBytes;
|
||||
}
|
||||
|
||||
/**
|
||||
* get success upload file bytes
|
||||
*
|
||||
* @return success upload file bytes
|
||||
*/
|
||||
public long getSuccessUploadBytes() {
|
||||
return this.successUploadBytes;
|
||||
}
|
||||
|
||||
/**
|
||||
* get total append bytes
|
||||
*
|
||||
* @return total append bytes
|
||||
*/
|
||||
public long getTotalAppendBytes() {
|
||||
return this.totalAppendBytes;
|
||||
}
|
||||
|
||||
/**
|
||||
* get success append bytes
|
||||
*
|
||||
* @return success append bytes
|
||||
*/
|
||||
public long getSuccessAppendBytes() {
|
||||
return this.successAppendBytes;
|
||||
}
|
||||
|
||||
/**
|
||||
* get total modify bytes
|
||||
*
|
||||
* @return total modify bytes
|
||||
*/
|
||||
public long getTotalModifyBytes() {
|
||||
return this.totalModifyBytes;
|
||||
}
|
||||
|
||||
/**
|
||||
* get success modify bytes
|
||||
*
|
||||
* @return success modify bytes
|
||||
*/
|
||||
public long getSuccessModifyBytes() {
|
||||
return this.successModifyBytes;
|
||||
}
|
||||
|
||||
/**
|
||||
* get total download file bytes
|
||||
*
|
||||
* @return total download file bytes
|
||||
*/
|
||||
public long getTotalDownloadloadBytes() {
|
||||
return this.totalDownloadloadBytes;
|
||||
}
|
||||
|
||||
/**
|
||||
* get success download file bytes
|
||||
*
|
||||
* @return success download file bytes
|
||||
*/
|
||||
public long getSuccessDownloadloadBytes() {
|
||||
return this.successDownloadloadBytes;
|
||||
}
|
||||
|
||||
/**
|
||||
* get total sync in bytes
|
||||
*
|
||||
* @return total sync in bytes
|
||||
*/
|
||||
public long getTotalSyncInBytes() {
|
||||
return this.totalSyncInBytes;
|
||||
}
|
||||
|
||||
/**
|
||||
* get success sync in bytes
|
||||
*
|
||||
* @return success sync in bytes
|
||||
*/
|
||||
public long getSuccessSyncInBytes() {
|
||||
return this.successSyncInBytes;
|
||||
}
|
||||
|
||||
/**
|
||||
* get total sync out bytes
|
||||
*
|
||||
* @return total sync out bytes
|
||||
*/
|
||||
public long getTotalSyncOutBytes() {
|
||||
return this.totalSyncOutBytes;
|
||||
}
|
||||
|
||||
/**
|
||||
* get success sync out bytes
|
||||
*
|
||||
* @return success sync out bytes
|
||||
*/
|
||||
public long getSuccessSyncOutBytes() {
|
||||
return this.successSyncOutBytes;
|
||||
}
|
||||
|
||||
/**
|
||||
* get total file opened count
|
||||
*
|
||||
* @return total file opened bytes
|
||||
*/
|
||||
public long getTotalFileOpenCount() {
|
||||
return this.totalFileOpenCount;
|
||||
}
|
||||
|
||||
/**
|
||||
* get success file opened count
|
||||
*
|
||||
* @return success file opened count
|
||||
*/
|
||||
public long getSuccessFileOpenCount() {
|
||||
return this.successFileOpenCount;
|
||||
}
|
||||
|
||||
/**
|
||||
* get total file read count
|
||||
*
|
||||
* @return total file read bytes
|
||||
*/
|
||||
public long getTotalFileReadCount() {
|
||||
return this.totalFileReadCount;
|
||||
}
|
||||
|
||||
/**
|
||||
* get success file read count
|
||||
*
|
||||
* @return success file read count
|
||||
*/
|
||||
public long getSuccessFileReadCount() {
|
||||
return this.successFileReadCount;
|
||||
}
|
||||
|
||||
/**
|
||||
* get total file write count
|
||||
*
|
||||
* @return total file write bytes
|
||||
*/
|
||||
public long getTotalFileWriteCount() {
|
||||
return this.totalFileWriteCount;
|
||||
}
|
||||
|
||||
/**
|
||||
* get success file write count
|
||||
*
|
||||
* @return success file write count
|
||||
*/
|
||||
public long getSuccessFileWriteCount() {
|
||||
return this.successFileWriteCount;
|
||||
}
|
||||
|
||||
/**
|
||||
* get last source update timestamp
|
||||
*
|
||||
* @return last source update timestamp
|
||||
*/
|
||||
public Date getLastSourceUpdate() {
|
||||
return this.lastSourceUpdate;
|
||||
}
|
||||
|
||||
/**
|
||||
* get last synced update timestamp
|
||||
*
|
||||
* @return last synced update timestamp
|
||||
*/
|
||||
public Date getLastSyncUpdate() {
|
||||
return this.lastSyncUpdate;
|
||||
}
|
||||
|
||||
/**
|
||||
* get last synced timestamp
|
||||
*
|
||||
* @return last synced timestamp
|
||||
*/
|
||||
public Date getLastSyncedTimestamp() {
|
||||
return this.lastSyncedTimestamp;
|
||||
}
|
||||
|
||||
/**
|
||||
* get last heart beat timestamp
|
||||
*
|
||||
* @return last heart beat timestamp
|
||||
*/
|
||||
public Date getLastHeartBeatTime() {
|
||||
return this.lastHeartBeatTime;
|
||||
}
|
||||
|
||||
/**
|
||||
* if the trunk server
|
||||
*
|
||||
* @return true for the trunk server, otherwise false
|
||||
*/
|
||||
public boolean isTrunkServer() {
|
||||
return this.ifTrunkServer;
|
||||
}
|
||||
|
||||
/**
|
||||
* get connection alloc count
|
||||
*
|
||||
* @return connection alloc count
|
||||
*/
|
||||
public int getConnectionAllocCount() {
|
||||
return this.connectionAllocCount;
|
||||
}
|
||||
|
||||
/**
|
||||
* get connection current count
|
||||
*
|
||||
* @return connection current count
|
||||
*/
|
||||
public int getConnectionCurrentCount() {
|
||||
return this.connectionCurrentCount;
|
||||
}
|
||||
|
||||
/**
|
||||
* get connection max count
|
||||
*
|
||||
* @return connection max count
|
||||
*/
|
||||
public int getConnectionMaxCount() {
|
||||
return this.connectionMaxCount;
|
||||
}
|
||||
|
||||
/**
|
||||
* set fields
|
||||
*
|
||||
* @param bs byte array
|
||||
* @param offset start offset
|
||||
*/
|
||||
public void setFields(byte[] bs, int offset) {
|
||||
this.status = byteValue(bs, offset, fieldsArray[FIELD_INDEX_STATUS]);
|
||||
this.id = stringValue(bs, offset, fieldsArray[FIELD_INDEX_ID]);
|
||||
this.ipAddr = stringValue(bs, offset, fieldsArray[FIELD_INDEX_IP_ADDR]);
|
||||
this.srcIpAddr = stringValue(bs, offset, fieldsArray[FIELD_INDEX_SRC_IP_ADDR]);
|
||||
this.domainName = stringValue(bs, offset, fieldsArray[FIELD_INDEX_DOMAIN_NAME]);
|
||||
this.version = stringValue(bs, offset, fieldsArray[FIELD_INDEX_VERSION]);
|
||||
this.totalMB = longValue(bs, offset, fieldsArray[FIELD_INDEX_TOTAL_MB]);
|
||||
this.freeMB = longValue(bs, offset, fieldsArray[FIELD_INDEX_FREE_MB]);
|
||||
this.uploadPriority = intValue(bs, offset, fieldsArray[FIELD_INDEX_UPLOAD_PRIORITY]);
|
||||
this.joinTime = dateValue(bs, offset, fieldsArray[FIELD_INDEX_JOIN_TIME]);
|
||||
this.upTime = dateValue(bs, offset, fieldsArray[FIELD_INDEX_UP_TIME]);
|
||||
this.storePathCount = intValue(bs, offset, fieldsArray[FIELD_INDEX_STORE_PATH_COUNT]);
|
||||
this.subdirCountPerPath = intValue(bs, offset, fieldsArray[FIELD_INDEX_SUBDIR_COUNT_PER_PATH]);
|
||||
this.storagePort = intValue(bs, offset, fieldsArray[FIELD_INDEX_STORAGE_PORT]);
|
||||
this.storageHttpPort = intValue(bs, offset, fieldsArray[FIELD_INDEX_STORAGE_HTTP_PORT]);
|
||||
this.currentWritePath = intValue(bs, offset, fieldsArray[FIELD_INDEX_CURRENT_WRITE_PATH]);
|
||||
|
||||
this.connectionAllocCount = int32Value(bs, offset, fieldsArray[FIELD_INDEX_CONNECTION_ALLOC_COUNT]);
|
||||
this.connectionCurrentCount = int32Value(bs, offset, fieldsArray[FIELD_INDEX_CONNECTION_CURRENT_COUNT]);
|
||||
this.connectionMaxCount = int32Value(bs, offset, fieldsArray[FIELD_INDEX_CONNECTION_MAX_COUNT]);
|
||||
|
||||
this.totalUploadCount = longValue(bs, offset, fieldsArray[FIELD_INDEX_TOTAL_UPLOAD_COUNT]);
|
||||
this.successUploadCount = longValue(bs, offset, fieldsArray[FIELD_INDEX_SUCCESS_UPLOAD_COUNT]);
|
||||
this.totalAppendCount = longValue(bs, offset, fieldsArray[FIELD_INDEX_TOTAL_APPEND_COUNT]);
|
||||
this.successAppendCount = longValue(bs, offset, fieldsArray[FIELD_INDEX_SUCCESS_APPEND_COUNT]);
|
||||
this.totalModifyCount = longValue(bs, offset, fieldsArray[FIELD_INDEX_TOTAL_MODIFY_COUNT]);
|
||||
this.successModifyCount = longValue(bs, offset, fieldsArray[FIELD_INDEX_SUCCESS_MODIFY_COUNT]);
|
||||
this.totalTruncateCount = longValue(bs, offset, fieldsArray[FIELD_INDEX_TOTAL_TRUNCATE_COUNT]);
|
||||
this.successTruncateCount = longValue(bs, offset, fieldsArray[FIELD_INDEX_SUCCESS_TRUNCATE_COUNT]);
|
||||
this.totalSetMetaCount = longValue(bs, offset, fieldsArray[FIELD_INDEX_TOTAL_SET_META_COUNT]);
|
||||
this.successSetMetaCount = longValue(bs, offset, fieldsArray[FIELD_INDEX_SUCCESS_SET_META_COUNT]);
|
||||
this.totalDeleteCount = longValue(bs, offset, fieldsArray[FIELD_INDEX_TOTAL_DELETE_COUNT]);
|
||||
this.successDeleteCount = longValue(bs, offset, fieldsArray[FIELD_INDEX_SUCCESS_DELETE_COUNT]);
|
||||
this.totalDownloadCount = longValue(bs, offset, fieldsArray[FIELD_INDEX_TOTAL_DOWNLOAD_COUNT]);
|
||||
this.successDownloadCount = longValue(bs, offset, fieldsArray[FIELD_INDEX_SUCCESS_DOWNLOAD_COUNT]);
|
||||
this.totalGetMetaCount = longValue(bs, offset, fieldsArray[FIELD_INDEX_TOTAL_GET_META_COUNT]);
|
||||
this.successGetMetaCount = longValue(bs, offset, fieldsArray[FIELD_INDEX_SUCCESS_GET_META_COUNT]);
|
||||
this.totalCreateLinkCount = longValue(bs, offset, fieldsArray[FIELD_INDEX_TOTAL_CREATE_LINK_COUNT]);
|
||||
this.successCreateLinkCount = longValue(bs, offset, fieldsArray[FIELD_INDEX_SUCCESS_CREATE_LINK_COUNT]);
|
||||
this.totalDeleteLinkCount = longValue(bs, offset, fieldsArray[FIELD_INDEX_TOTAL_DELETE_LINK_COUNT]);
|
||||
this.successDeleteLinkCount = longValue(bs, offset, fieldsArray[FIELD_INDEX_SUCCESS_DELETE_LINK_COUNT]);
|
||||
this.totalUploadBytes = longValue(bs, offset, fieldsArray[FIELD_INDEX_TOTAL_UPLOAD_BYTES]);
|
||||
this.successUploadBytes = longValue(bs, offset, fieldsArray[FIELD_INDEX_SUCCESS_UPLOAD_BYTES]);
|
||||
this.totalAppendBytes = longValue(bs, offset, fieldsArray[FIELD_INDEX_TOTAL_APPEND_BYTES]);
|
||||
this.successAppendBytes = longValue(bs, offset, fieldsArray[FIELD_INDEX_SUCCESS_APPEND_BYTES]);
|
||||
this.totalModifyBytes = longValue(bs, offset, fieldsArray[FIELD_INDEX_TOTAL_MODIFY_BYTES]);
|
||||
this.successModifyBytes = longValue(bs, offset, fieldsArray[FIELD_INDEX_SUCCESS_MODIFY_BYTES]);
|
||||
this.totalDownloadloadBytes = longValue(bs, offset, fieldsArray[FIELD_INDEX_TOTAL_DOWNLOAD_BYTES]);
|
||||
this.successDownloadloadBytes = longValue(bs, offset, fieldsArray[FIELD_INDEX_SUCCESS_DOWNLOAD_BYTES]);
|
||||
this.totalSyncInBytes = longValue(bs, offset, fieldsArray[FIELD_INDEX_TOTAL_SYNC_IN_BYTES]);
|
||||
this.successSyncInBytes = longValue(bs, offset, fieldsArray[FIELD_INDEX_SUCCESS_SYNC_IN_BYTES]);
|
||||
this.totalSyncOutBytes = longValue(bs, offset, fieldsArray[FIELD_INDEX_TOTAL_SYNC_OUT_BYTES]);
|
||||
this.successSyncOutBytes = longValue(bs, offset, fieldsArray[FIELD_INDEX_SUCCESS_SYNC_OUT_BYTES]);
|
||||
this.totalFileOpenCount = longValue(bs, offset, fieldsArray[FIELD_INDEX_TOTAL_FILE_OPEN_COUNT]);
|
||||
this.successFileOpenCount = longValue(bs, offset, fieldsArray[FIELD_INDEX_SUCCESS_FILE_OPEN_COUNT]);
|
||||
this.totalFileReadCount = longValue(bs, offset, fieldsArray[FIELD_INDEX_TOTAL_FILE_READ_COUNT]);
|
||||
this.successFileReadCount = longValue(bs, offset, fieldsArray[FIELD_INDEX_SUCCESS_FILE_READ_COUNT]);
|
||||
this.totalFileWriteCount = longValue(bs, offset, fieldsArray[FIELD_INDEX_TOTAL_FILE_WRITE_COUNT]);
|
||||
this.successFileWriteCount = longValue(bs, offset, fieldsArray[FIELD_INDEX_SUCCESS_FILE_WRITE_COUNT]);
|
||||
this.lastSourceUpdate = dateValue(bs, offset, fieldsArray[FIELD_INDEX_LAST_SOURCE_UPDATE]);
|
||||
this.lastSyncUpdate = dateValue(bs, offset, fieldsArray[FIELD_INDEX_LAST_SYNC_UPDATE]);
|
||||
this.lastSyncedTimestamp = dateValue(bs, offset, fieldsArray[FIELD_INDEX_LAST_SYNCED_TIMESTAMP]);
|
||||
this.lastHeartBeatTime = dateValue(bs, offset, fieldsArray[FIELD_INDEX_LAST_HEART_BEAT_TIME]);
|
||||
this.ifTrunkServer = booleanValue(bs, offset, fieldsArray[FIELD_INDEX_IF_TRUNK_FILE]);
|
||||
}
|
||||
}
|
||||
+809
@@ -0,0 +1,809 @@
|
||||
/**
|
||||
* Copyright (C) 2008 Happy Fish / YuQing
|
||||
* <p>
|
||||
* FastDFS Java Client may be copied only under the terms of the GNU Lesser
|
||||
* General Public License (LGPL).
|
||||
* Please visit the FastDFS Home Page https://github.com/happyfish100/fastdfs for more detail.
|
||||
*/
|
||||
|
||||
package com.csource.fastdfs;
|
||||
|
||||
|
||||
import com.csource.common.MyException;
|
||||
import com.csource.fastdfs.pool.Connection;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.OutputStream;
|
||||
import java.util.Arrays;
|
||||
|
||||
/**
|
||||
* Tracker client for request to tracker server
|
||||
* Note: the instance of this class is NOT thread safe !!!
|
||||
*
|
||||
* @author Happy Fish / YuQing
|
||||
* @version Version 1.19
|
||||
*/
|
||||
public class TrackerClient {
|
||||
protected TrackerGroup tracker_group;
|
||||
protected byte errno;
|
||||
|
||||
/**
|
||||
* constructor with global tracker group
|
||||
*/
|
||||
public TrackerClient() {
|
||||
this.tracker_group = ClientGlobal.g_tracker_group;
|
||||
}
|
||||
|
||||
/**
|
||||
* constructor with specified tracker group
|
||||
*
|
||||
* @param tracker_group the tracker group object
|
||||
*/
|
||||
public TrackerClient(TrackerGroup tracker_group) {
|
||||
this.tracker_group = tracker_group;
|
||||
}
|
||||
|
||||
/**
|
||||
* get the error code of last call
|
||||
*
|
||||
* @return the error code of last call
|
||||
*/
|
||||
public byte getErrorCode() {
|
||||
return this.errno;
|
||||
}
|
||||
|
||||
/**
|
||||
* get a connection to tracker server
|
||||
*
|
||||
* @return tracker server Socket object, return null if fail
|
||||
*/
|
||||
public TrackerServer getTrackerServer() throws IOException {
|
||||
return this.tracker_group.getTrackerServer();
|
||||
}
|
||||
|
||||
/**
|
||||
* query storage server to upload file
|
||||
*
|
||||
* @param trackerServer the tracker server
|
||||
* @return storage server Socket object, return null if fail
|
||||
*/
|
||||
public StorageServer getStoreStorage(TrackerServer trackerServer) throws IOException, MyException {
|
||||
final String groupName = null;
|
||||
return this.getStoreStorage(trackerServer, groupName);
|
||||
}
|
||||
|
||||
public Connection getConnection(TrackerServer trackerServer) throws IOException, MyException {
|
||||
Connection connection = null;
|
||||
int length = this.tracker_group.tracker_servers.length;
|
||||
boolean failOver = length > 1 && trackerServer == null;
|
||||
try {
|
||||
if (trackerServer == null) {
|
||||
trackerServer = getTrackerServer();
|
||||
if (trackerServer == null) {
|
||||
throw new MyException("tracker server is empty!");
|
||||
}
|
||||
}
|
||||
connection = trackerServer.getConnection();
|
||||
} catch (IOException e) {
|
||||
if (failOver) {
|
||||
System.err.println("trackerServer get connection error, emsg:" + e.getMessage());
|
||||
} else {
|
||||
throw e;
|
||||
}
|
||||
} catch (MyException e) {
|
||||
if (failOver) {
|
||||
System.err.println("trackerServer get connection error, emsg:" + e.getMessage());
|
||||
} else {
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
if (connection != null || !failOver) {
|
||||
return connection;
|
||||
}
|
||||
//do fail over
|
||||
int currentIndex = 0;
|
||||
if (trackerServer != null) {
|
||||
currentIndex = trackerServer.getIndex();
|
||||
}
|
||||
int failOverCount = 0;
|
||||
while (failOverCount < length - 1) {
|
||||
failOverCount++;
|
||||
currentIndex++;
|
||||
if (currentIndex >= length) {
|
||||
currentIndex = 0;
|
||||
}
|
||||
try {
|
||||
trackerServer = this.tracker_group.getTrackerServer(currentIndex);
|
||||
if (trackerServer == null) {
|
||||
throw new MyException("tracker server is empty!");
|
||||
}
|
||||
return trackerServer.getConnection();
|
||||
} catch (IOException e) {
|
||||
System.err.println("fail over trackerServer get connection error, failOverCount:" + failOverCount + "," + e.getMessage());
|
||||
if (failOverCount == length - 1) {
|
||||
throw e;
|
||||
}
|
||||
|
||||
} catch (MyException e) {
|
||||
System.err.println("fail over trackerServer get connection error, failOverCount:" + failOverCount + ", " + e.getMessage());
|
||||
if (failOverCount == length - 1) {
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* query storage server to upload file
|
||||
*
|
||||
* @param trackerServer the tracker server
|
||||
* @param groupName the group name to upload file to, can be empty
|
||||
* @return storage server object, return null if fail
|
||||
*/
|
||||
public StorageServer getStoreStorage(TrackerServer trackerServer, String groupName) throws IOException, MyException {
|
||||
byte[] header;
|
||||
String ip_addr;
|
||||
int port;
|
||||
byte cmd;
|
||||
int out_len;
|
||||
byte store_path;
|
||||
Connection connection = getConnection(trackerServer);
|
||||
OutputStream out = connection.getOutputStream();
|
||||
|
||||
try {
|
||||
if (groupName == null || groupName.length() == 0) {
|
||||
cmd = ProtoCommon.TRACKER_PROTO_CMD_SERVICE_QUERY_STORE_WITHOUT_GROUP_ONE;
|
||||
out_len = 0;
|
||||
} else {
|
||||
cmd = ProtoCommon.TRACKER_PROTO_CMD_SERVICE_QUERY_STORE_WITH_GROUP_ONE;
|
||||
out_len = ProtoCommon.FDFS_GROUP_NAME_MAX_LEN;
|
||||
}
|
||||
header = ProtoCommon.packHeader(cmd, out_len, (byte) 0);
|
||||
out.write(header);
|
||||
|
||||
if (groupName != null && groupName.length() > 0) {
|
||||
byte[] bGroupName;
|
||||
byte[] bs;
|
||||
int group_len;
|
||||
|
||||
bs = groupName.getBytes(ClientGlobal.g_charset);
|
||||
bGroupName = new byte[ProtoCommon.FDFS_GROUP_NAME_MAX_LEN];
|
||||
|
||||
if (bs.length <= ProtoCommon.FDFS_GROUP_NAME_MAX_LEN) {
|
||||
group_len = bs.length;
|
||||
} else {
|
||||
group_len = ProtoCommon.FDFS_GROUP_NAME_MAX_LEN;
|
||||
}
|
||||
Arrays.fill(bGroupName, (byte) 0);
|
||||
System.arraycopy(bs, 0, bGroupName, 0, group_len);
|
||||
out.write(bGroupName);
|
||||
}
|
||||
|
||||
ProtoCommon.RecvPackageInfo pkgInfo = ProtoCommon.recvPackage(connection.getInputStream(),
|
||||
ProtoCommon.TRACKER_PROTO_CMD_RESP,
|
||||
ProtoCommon.TRACKER_QUERY_STORAGE_STORE_BODY_LEN);
|
||||
this.errno = pkgInfo.errno;
|
||||
if (pkgInfo.errno != 0) {
|
||||
return null;
|
||||
}
|
||||
|
||||
ip_addr = new String(pkgInfo.body, ProtoCommon.FDFS_GROUP_NAME_MAX_LEN, ProtoCommon.FDFS_IPADDR_SIZE - 1).trim();
|
||||
|
||||
port = (int) ProtoCommon.buff2long(pkgInfo.body, ProtoCommon.FDFS_GROUP_NAME_MAX_LEN
|
||||
+ ProtoCommon.FDFS_IPADDR_SIZE - 1);
|
||||
store_path = pkgInfo.body[ProtoCommon.TRACKER_QUERY_STORAGE_STORE_BODY_LEN - 1];
|
||||
|
||||
return new StorageServer(ip_addr, port, store_path);
|
||||
} catch (IOException ex) {
|
||||
try {
|
||||
connection.close();
|
||||
} catch (IOException ex1) {
|
||||
ex1.printStackTrace();
|
||||
} finally {
|
||||
connection = null;
|
||||
}
|
||||
throw ex;
|
||||
} finally {
|
||||
if (connection != null) {
|
||||
try {
|
||||
connection.release();
|
||||
} catch (IOException ex1) {
|
||||
ex1.printStackTrace();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* query storage servers to upload file
|
||||
*
|
||||
* @param trackerServer the tracker server
|
||||
* @param groupName the group name to upload file to, can be empty
|
||||
* @return storage servers, return null if fail
|
||||
*/
|
||||
public StorageServer[] getStoreStorages(TrackerServer trackerServer, String groupName) throws IOException, MyException {
|
||||
byte[] header;
|
||||
String ip_addr;
|
||||
int port;
|
||||
byte cmd;
|
||||
int out_len;
|
||||
Connection connection = getConnection(trackerServer);
|
||||
OutputStream out = connection.getOutputStream();
|
||||
|
||||
try {
|
||||
if (groupName == null || groupName.length() == 0) {
|
||||
cmd = ProtoCommon.TRACKER_PROTO_CMD_SERVICE_QUERY_STORE_WITHOUT_GROUP_ALL;
|
||||
out_len = 0;
|
||||
} else {
|
||||
cmd = ProtoCommon.TRACKER_PROTO_CMD_SERVICE_QUERY_STORE_WITH_GROUP_ALL;
|
||||
out_len = ProtoCommon.FDFS_GROUP_NAME_MAX_LEN;
|
||||
}
|
||||
header = ProtoCommon.packHeader(cmd, out_len, (byte) 0);
|
||||
out.write(header);
|
||||
|
||||
if (groupName != null && groupName.length() > 0) {
|
||||
byte[] bGroupName;
|
||||
byte[] bs;
|
||||
int group_len;
|
||||
|
||||
bs = groupName.getBytes(ClientGlobal.g_charset);
|
||||
bGroupName = new byte[ProtoCommon.FDFS_GROUP_NAME_MAX_LEN];
|
||||
|
||||
if (bs.length <= ProtoCommon.FDFS_GROUP_NAME_MAX_LEN) {
|
||||
group_len = bs.length;
|
||||
} else {
|
||||
group_len = ProtoCommon.FDFS_GROUP_NAME_MAX_LEN;
|
||||
}
|
||||
Arrays.fill(bGroupName, (byte) 0);
|
||||
System.arraycopy(bs, 0, bGroupName, 0, group_len);
|
||||
out.write(bGroupName);
|
||||
}
|
||||
|
||||
ProtoCommon.RecvPackageInfo pkgInfo = ProtoCommon.recvPackage(connection.getInputStream(),
|
||||
ProtoCommon.TRACKER_PROTO_CMD_RESP, -1);
|
||||
this.errno = pkgInfo.errno;
|
||||
if (pkgInfo.errno != 0) {
|
||||
return null;
|
||||
}
|
||||
|
||||
if (pkgInfo.body.length < ProtoCommon.TRACKER_QUERY_STORAGE_STORE_BODY_LEN) {
|
||||
this.errno = ProtoCommon.ERR_NO_EINVAL;
|
||||
return null;
|
||||
}
|
||||
|
||||
int ipPortLen = pkgInfo.body.length - (ProtoCommon.FDFS_GROUP_NAME_MAX_LEN + 1);
|
||||
final int recordLength = ProtoCommon.FDFS_IPADDR_SIZE - 1 + ProtoCommon.FDFS_PROTO_PKG_LEN_SIZE;
|
||||
|
||||
if (ipPortLen % recordLength != 0) {
|
||||
this.errno = ProtoCommon.ERR_NO_EINVAL;
|
||||
return null;
|
||||
}
|
||||
|
||||
int serverCount = ipPortLen / recordLength;
|
||||
if (serverCount > 16) {
|
||||
this.errno = ProtoCommon.ERR_NO_ENOSPC;
|
||||
return null;
|
||||
}
|
||||
|
||||
StorageServer[] results = new StorageServer[serverCount];
|
||||
byte store_path = pkgInfo.body[pkgInfo.body.length - 1];
|
||||
int offset = ProtoCommon.FDFS_GROUP_NAME_MAX_LEN;
|
||||
|
||||
for (int i = 0; i < serverCount; i++) {
|
||||
ip_addr = new String(pkgInfo.body, offset, ProtoCommon.FDFS_IPADDR_SIZE - 1).trim();
|
||||
offset += ProtoCommon.FDFS_IPADDR_SIZE - 1;
|
||||
|
||||
port = (int) ProtoCommon.buff2long(pkgInfo.body, offset);
|
||||
offset += ProtoCommon.FDFS_PROTO_PKG_LEN_SIZE;
|
||||
|
||||
results[i] = new StorageServer(ip_addr, port, store_path);
|
||||
}
|
||||
|
||||
return results;
|
||||
} catch (IOException ex) {
|
||||
try {
|
||||
connection.close();
|
||||
} catch (IOException ex1) {
|
||||
ex1.printStackTrace();
|
||||
} finally {
|
||||
connection = null;
|
||||
}
|
||||
throw ex;
|
||||
} finally {
|
||||
if (connection != null) {
|
||||
try {
|
||||
connection.release();
|
||||
} catch (IOException ex1) {
|
||||
ex1.printStackTrace();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* query storage server to download file
|
||||
*
|
||||
* @param trackerServer the tracker server
|
||||
* @param groupName the group name of storage server
|
||||
* @param filename filename on storage server
|
||||
* @return storage server Socket object, return null if fail
|
||||
*/
|
||||
public StorageServer getFetchStorage(TrackerServer trackerServer,
|
||||
String groupName, String filename) throws IOException, MyException {
|
||||
ServerInfo[] servers = this.getStorages(trackerServer, ProtoCommon.TRACKER_PROTO_CMD_SERVICE_QUERY_FETCH_ONE,
|
||||
groupName, filename);
|
||||
if (servers == null) {
|
||||
return null;
|
||||
} else {
|
||||
return new StorageServer(servers[0].getIpAddr(), servers[0].getPort(), 0);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* query storage server to update file (delete file or set meta data)
|
||||
*
|
||||
* @param trackerServer the tracker server
|
||||
* @param groupName the group name of storage server
|
||||
* @param filename filename on storage server
|
||||
* @return storage server Socket object, return null if fail
|
||||
*/
|
||||
public StorageServer getUpdateStorage(TrackerServer trackerServer,
|
||||
String groupName, String filename) throws IOException, MyException {
|
||||
ServerInfo[] servers = this.getStorages(trackerServer, ProtoCommon.TRACKER_PROTO_CMD_SERVICE_QUERY_UPDATE,
|
||||
groupName, filename);
|
||||
if (servers == null) {
|
||||
return null;
|
||||
} else {
|
||||
return new StorageServer(servers[0].getIpAddr(), servers[0].getPort(), 0);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* get storage servers to download file
|
||||
*
|
||||
* @param trackerServer the tracker server
|
||||
* @param groupName the group name of storage server
|
||||
* @param filename filename on storage server
|
||||
* @return storage servers, return null if fail
|
||||
*/
|
||||
public ServerInfo[] getFetchStorages(TrackerServer trackerServer,
|
||||
String groupName, String filename) throws IOException, MyException {
|
||||
return this.getStorages(trackerServer, ProtoCommon.TRACKER_PROTO_CMD_SERVICE_QUERY_FETCH_ALL,
|
||||
groupName, filename);
|
||||
}
|
||||
|
||||
/**
|
||||
* query storage server to download file
|
||||
*
|
||||
* @param trackerServer the tracker server
|
||||
* @param cmd command code, ProtoCommon.TRACKER_PROTO_CMD_SERVICE_QUERY_FETCH_ONE or
|
||||
* ProtoCommon.TRACKER_PROTO_CMD_SERVICE_QUERY_UPDATE
|
||||
* @param groupName the group name of storage server
|
||||
* @param filename filename on storage server
|
||||
* @return storage server Socket object, return null if fail
|
||||
*/
|
||||
protected ServerInfo[] getStorages(TrackerServer trackerServer,
|
||||
byte cmd, String groupName, String filename) throws IOException, MyException {
|
||||
byte[] header;
|
||||
byte[] bFileName;
|
||||
byte[] bGroupName;
|
||||
byte[] bs;
|
||||
int len;
|
||||
String ip_addr;
|
||||
int port;
|
||||
Connection connection = getConnection(trackerServer);
|
||||
OutputStream out = connection.getOutputStream();
|
||||
|
||||
try {
|
||||
bs = groupName.getBytes(ClientGlobal.g_charset);
|
||||
bGroupName = new byte[ProtoCommon.FDFS_GROUP_NAME_MAX_LEN];
|
||||
bFileName = filename.getBytes(ClientGlobal.g_charset);
|
||||
|
||||
if (bs.length <= ProtoCommon.FDFS_GROUP_NAME_MAX_LEN) {
|
||||
len = bs.length;
|
||||
} else {
|
||||
len = ProtoCommon.FDFS_GROUP_NAME_MAX_LEN;
|
||||
}
|
||||
Arrays.fill(bGroupName, (byte) 0);
|
||||
System.arraycopy(bs, 0, bGroupName, 0, len);
|
||||
|
||||
header = ProtoCommon.packHeader(cmd, ProtoCommon.FDFS_GROUP_NAME_MAX_LEN + bFileName.length, (byte) 0);
|
||||
byte[] wholePkg = new byte[header.length + bGroupName.length + bFileName.length];
|
||||
System.arraycopy(header, 0, wholePkg, 0, header.length);
|
||||
System.arraycopy(bGroupName, 0, wholePkg, header.length, bGroupName.length);
|
||||
System.arraycopy(bFileName, 0, wholePkg, header.length + bGroupName.length, bFileName.length);
|
||||
out.write(wholePkg);
|
||||
|
||||
ProtoCommon.RecvPackageInfo pkgInfo = ProtoCommon.recvPackage(connection.getInputStream(),
|
||||
ProtoCommon.TRACKER_PROTO_CMD_RESP, -1);
|
||||
this.errno = pkgInfo.errno;
|
||||
if (pkgInfo.errno != 0) {
|
||||
return null;
|
||||
}
|
||||
|
||||
if (pkgInfo.body.length < ProtoCommon.TRACKER_QUERY_STORAGE_FETCH_BODY_LEN) {
|
||||
throw new IOException("Invalid body length: " + pkgInfo.body.length);
|
||||
}
|
||||
|
||||
if ((pkgInfo.body.length - ProtoCommon.TRACKER_QUERY_STORAGE_FETCH_BODY_LEN) % (ProtoCommon.FDFS_IPADDR_SIZE - 1) != 0) {
|
||||
throw new IOException("Invalid body length: " + pkgInfo.body.length);
|
||||
}
|
||||
|
||||
int server_count = 1 + (pkgInfo.body.length - ProtoCommon.TRACKER_QUERY_STORAGE_FETCH_BODY_LEN) / (ProtoCommon.FDFS_IPADDR_SIZE - 1);
|
||||
|
||||
ip_addr = new String(pkgInfo.body, ProtoCommon.FDFS_GROUP_NAME_MAX_LEN, ProtoCommon.FDFS_IPADDR_SIZE - 1).trim();
|
||||
int offset = ProtoCommon.FDFS_GROUP_NAME_MAX_LEN + ProtoCommon.FDFS_IPADDR_SIZE - 1;
|
||||
|
||||
port = (int) ProtoCommon.buff2long(pkgInfo.body, offset);
|
||||
offset += ProtoCommon.FDFS_PROTO_PKG_LEN_SIZE;
|
||||
|
||||
ServerInfo[] servers = new ServerInfo[server_count];
|
||||
servers[0] = new ServerInfo(ip_addr, port);
|
||||
for (int i = 1; i < server_count; i++) {
|
||||
servers[i] = new ServerInfo(new String(pkgInfo.body, offset, ProtoCommon.FDFS_IPADDR_SIZE - 1).trim(), port);
|
||||
offset += ProtoCommon.FDFS_IPADDR_SIZE - 1;
|
||||
}
|
||||
|
||||
return servers;
|
||||
} catch (IOException ex) {
|
||||
try {
|
||||
connection.close();
|
||||
} catch (IOException ex1) {
|
||||
ex1.printStackTrace();
|
||||
} finally {
|
||||
connection = null;
|
||||
}
|
||||
|
||||
throw ex;
|
||||
} finally {
|
||||
if (connection != null) {
|
||||
try {
|
||||
connection.release();
|
||||
} catch (IOException ex1) {
|
||||
ex1.printStackTrace();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* query storage server to download file
|
||||
*
|
||||
* @param trackerServer the tracker server
|
||||
* @param file_id the file id(including group name and filename)
|
||||
* @return storage server Socket object, return null if fail
|
||||
*/
|
||||
public StorageServer getFetchStorage1(TrackerServer trackerServer, String file_id) throws IOException, MyException {
|
||||
String[] parts = new String[2];
|
||||
this.errno = StorageClient1.split_file_id(file_id, parts);
|
||||
if (this.errno != 0) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return this.getFetchStorage(trackerServer, parts[0], parts[1]);
|
||||
}
|
||||
|
||||
/**
|
||||
* get storage servers to download file
|
||||
*
|
||||
* @param trackerServer the tracker server
|
||||
* @param file_id the file id(including group name and filename)
|
||||
* @return storage servers, return null if fail
|
||||
*/
|
||||
public ServerInfo[] getFetchStorages1(TrackerServer trackerServer, String file_id) throws IOException, MyException {
|
||||
String[] parts = new String[2];
|
||||
this.errno = StorageClient1.split_file_id(file_id, parts);
|
||||
if (this.errno != 0) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return this.getFetchStorages(trackerServer, parts[0], parts[1]);
|
||||
}
|
||||
|
||||
/**
|
||||
* list groups
|
||||
*
|
||||
* @param trackerServer the tracker server
|
||||
* @return group stat array, return null if fail
|
||||
*/
|
||||
public StructGroupStat[] listGroups(TrackerServer trackerServer) throws IOException, MyException {
|
||||
byte[] header;
|
||||
String ip_addr;
|
||||
int port;
|
||||
byte cmd;
|
||||
int out_len;
|
||||
byte store_path;
|
||||
Connection connection = getConnection(trackerServer);
|
||||
OutputStream out = connection.getOutputStream();
|
||||
|
||||
try {
|
||||
header = ProtoCommon.packHeader(ProtoCommon.TRACKER_PROTO_CMD_SERVER_LIST_GROUP, 0, (byte) 0);
|
||||
out.write(header);
|
||||
|
||||
ProtoCommon.RecvPackageInfo pkgInfo = ProtoCommon.recvPackage(connection.getInputStream(),
|
||||
ProtoCommon.TRACKER_PROTO_CMD_RESP, -1);
|
||||
this.errno = pkgInfo.errno;
|
||||
if (pkgInfo.errno != 0) {
|
||||
return null;
|
||||
}
|
||||
|
||||
ProtoStructDecoder<StructGroupStat> decoder = new ProtoStructDecoder<StructGroupStat>();
|
||||
return decoder.decode(pkgInfo.body, StructGroupStat.class, StructGroupStat.getFieldsTotalSize());
|
||||
} catch (IOException ex) {
|
||||
try {
|
||||
connection.close();
|
||||
} catch (IOException ex1) {
|
||||
ex1.printStackTrace();
|
||||
} finally {
|
||||
connection = null;
|
||||
}
|
||||
throw ex;
|
||||
} catch (Exception ex) {
|
||||
ex.printStackTrace();
|
||||
this.errno = ProtoCommon.ERR_NO_EINVAL;
|
||||
return null;
|
||||
} finally {
|
||||
if (connection != null) {
|
||||
try {
|
||||
connection.release();
|
||||
} catch (IOException ex1) {
|
||||
ex1.printStackTrace();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* query storage server stat info of the group
|
||||
*
|
||||
* @param trackerServer the tracker server
|
||||
* @param groupName the group name of storage server
|
||||
* @return storage server stat array, return null if fail
|
||||
*/
|
||||
public StructStorageStat[] listStorages(TrackerServer trackerServer, String groupName) throws IOException, MyException {
|
||||
final String storageIpAddr = null;
|
||||
return this.listStorages(trackerServer, groupName, storageIpAddr);
|
||||
}
|
||||
|
||||
/**
|
||||
* query storage server stat info of the group
|
||||
*
|
||||
* @param trackerServer the tracker server
|
||||
* @param groupName the group name of storage server
|
||||
* @param storageIpAddr the storage server ip address, can be null or empty
|
||||
* @return storage server stat array, return null if fail
|
||||
*/
|
||||
public StructStorageStat[] listStorages(TrackerServer trackerServer,
|
||||
String groupName, String storageIpAddr) throws IOException, MyException {
|
||||
byte[] header;
|
||||
byte[] bGroupName;
|
||||
byte[] bs;
|
||||
int len;
|
||||
Connection connection = getConnection(trackerServer);
|
||||
OutputStream out = connection.getOutputStream();
|
||||
|
||||
try {
|
||||
bs = groupName.getBytes(ClientGlobal.g_charset);
|
||||
bGroupName = new byte[ProtoCommon.FDFS_GROUP_NAME_MAX_LEN];
|
||||
|
||||
if (bs.length <= ProtoCommon.FDFS_GROUP_NAME_MAX_LEN) {
|
||||
len = bs.length;
|
||||
} else {
|
||||
len = ProtoCommon.FDFS_GROUP_NAME_MAX_LEN;
|
||||
}
|
||||
Arrays.fill(bGroupName, (byte) 0);
|
||||
System.arraycopy(bs, 0, bGroupName, 0, len);
|
||||
|
||||
int ipAddrLen;
|
||||
byte[] bIpAddr;
|
||||
if (storageIpAddr != null && storageIpAddr.length() > 0) {
|
||||
bIpAddr = storageIpAddr.getBytes(ClientGlobal.g_charset);
|
||||
if (bIpAddr.length < ProtoCommon.FDFS_IPADDR_SIZE) {
|
||||
ipAddrLen = bIpAddr.length;
|
||||
} else {
|
||||
ipAddrLen = ProtoCommon.FDFS_IPADDR_SIZE - 1;
|
||||
}
|
||||
} else {
|
||||
bIpAddr = null;
|
||||
ipAddrLen = 0;
|
||||
}
|
||||
|
||||
header = ProtoCommon.packHeader(ProtoCommon.TRACKER_PROTO_CMD_SERVER_LIST_STORAGE, ProtoCommon.FDFS_GROUP_NAME_MAX_LEN + ipAddrLen, (byte) 0);
|
||||
byte[] wholePkg = new byte[header.length + bGroupName.length + ipAddrLen];
|
||||
System.arraycopy(header, 0, wholePkg, 0, header.length);
|
||||
System.arraycopy(bGroupName, 0, wholePkg, header.length, bGroupName.length);
|
||||
if (ipAddrLen > 0) {
|
||||
System.arraycopy(bIpAddr, 0, wholePkg, header.length + bGroupName.length, ipAddrLen);
|
||||
}
|
||||
out.write(wholePkg);
|
||||
|
||||
ProtoCommon.RecvPackageInfo pkgInfo = ProtoCommon.recvPackage(connection.getInputStream(),
|
||||
ProtoCommon.TRACKER_PROTO_CMD_RESP, -1);
|
||||
this.errno = pkgInfo.errno;
|
||||
if (pkgInfo.errno != 0) {
|
||||
return null;
|
||||
}
|
||||
|
||||
ProtoStructDecoder<StructStorageStat> decoder = new ProtoStructDecoder<StructStorageStat>();
|
||||
return decoder.decode(pkgInfo.body, StructStorageStat.class, StructStorageStat.getFieldsTotalSize());
|
||||
} catch (IOException ex) {
|
||||
try {
|
||||
connection.close();
|
||||
} catch (IOException ex1) {
|
||||
ex1.printStackTrace();
|
||||
}
|
||||
|
||||
throw ex;
|
||||
} catch (Exception ex) {
|
||||
ex.printStackTrace();
|
||||
this.errno = ProtoCommon.ERR_NO_EINVAL;
|
||||
return null;
|
||||
} finally {
|
||||
if (connection != null) {
|
||||
try {
|
||||
connection.release();
|
||||
} catch (IOException ex1) {
|
||||
ex1.printStackTrace();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* delete a storage server from the tracker server
|
||||
*
|
||||
* @param trackerServer the connected tracker server
|
||||
* @param groupName the group name of storage server
|
||||
* @param storageIpAddr the storage server ip address
|
||||
* @return true for success, false for fail
|
||||
*/
|
||||
private boolean deleteStorage(TrackerServer trackerServer,
|
||||
String groupName, String storageIpAddr) throws IOException, MyException {
|
||||
byte[] header;
|
||||
byte[] bGroupName;
|
||||
byte[] bs;
|
||||
int len;
|
||||
Connection connection;
|
||||
|
||||
connection = trackerServer.getConnection();
|
||||
OutputStream out = connection.getOutputStream();
|
||||
|
||||
try {
|
||||
bs = groupName.getBytes(ClientGlobal.g_charset);
|
||||
bGroupName = new byte[ProtoCommon.FDFS_GROUP_NAME_MAX_LEN];
|
||||
|
||||
if (bs.length <= ProtoCommon.FDFS_GROUP_NAME_MAX_LEN) {
|
||||
len = bs.length;
|
||||
} else {
|
||||
len = ProtoCommon.FDFS_GROUP_NAME_MAX_LEN;
|
||||
}
|
||||
Arrays.fill(bGroupName, (byte) 0);
|
||||
System.arraycopy(bs, 0, bGroupName, 0, len);
|
||||
|
||||
int ipAddrLen;
|
||||
byte[] bIpAddr = storageIpAddr.getBytes(ClientGlobal.g_charset);
|
||||
if (bIpAddr.length < ProtoCommon.FDFS_IPADDR_SIZE) {
|
||||
ipAddrLen = bIpAddr.length;
|
||||
} else {
|
||||
ipAddrLen = ProtoCommon.FDFS_IPADDR_SIZE - 1;
|
||||
}
|
||||
|
||||
header = ProtoCommon.packHeader(ProtoCommon.TRACKER_PROTO_CMD_SERVER_DELETE_STORAGE, ProtoCommon.FDFS_GROUP_NAME_MAX_LEN + ipAddrLen, (byte) 0);
|
||||
byte[] wholePkg = new byte[header.length + bGroupName.length + ipAddrLen];
|
||||
System.arraycopy(header, 0, wholePkg, 0, header.length);
|
||||
System.arraycopy(bGroupName, 0, wholePkg, header.length, bGroupName.length);
|
||||
System.arraycopy(bIpAddr, 0, wholePkg, header.length + bGroupName.length, ipAddrLen);
|
||||
out.write(wholePkg);
|
||||
|
||||
ProtoCommon.RecvPackageInfo pkgInfo = ProtoCommon.recvPackage(connection.getInputStream(),
|
||||
ProtoCommon.TRACKER_PROTO_CMD_RESP, 0);
|
||||
this.errno = pkgInfo.errno;
|
||||
return pkgInfo.errno == 0;
|
||||
} catch (IOException e) {
|
||||
try {
|
||||
connection.close();
|
||||
} finally {
|
||||
connection = null;
|
||||
}
|
||||
throw e;
|
||||
} finally {
|
||||
if (connection != null) {
|
||||
connection.release();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* delete a storage server from the global FastDFS cluster
|
||||
*
|
||||
* @param groupName the group name of storage server
|
||||
* @param storageIpAddr the storage server ip address
|
||||
* @return true for success, false for fail
|
||||
*/
|
||||
public boolean deleteStorage(String groupName, String storageIpAddr) throws IOException, MyException {
|
||||
return this.deleteStorage(ClientGlobal.g_tracker_group, groupName, storageIpAddr);
|
||||
}
|
||||
|
||||
/**
|
||||
* delete a storage server from the FastDFS cluster
|
||||
*
|
||||
* @param trackerGroup the tracker server group
|
||||
* @param groupName the group name of storage server
|
||||
* @param storageIpAddr the storage server ip address
|
||||
* @return true for success, false for fail
|
||||
*/
|
||||
public boolean deleteStorage(TrackerGroup trackerGroup,
|
||||
String groupName, String storageIpAddr) throws IOException, MyException {
|
||||
int serverIndex;
|
||||
int notFoundCount;
|
||||
TrackerServer trackerServer;
|
||||
|
||||
notFoundCount = 0;
|
||||
for (serverIndex = 0; serverIndex < trackerGroup.tracker_servers.length; serverIndex++) {
|
||||
try {
|
||||
trackerServer = trackerGroup.getTrackerServer(serverIndex);
|
||||
} catch (IOException ex) {
|
||||
ex.printStackTrace(System.err);
|
||||
this.errno = ProtoCommon.ECONNREFUSED;
|
||||
return false;
|
||||
}
|
||||
StructStorageStat[] storageStats = listStorages(trackerServer, groupName, storageIpAddr);
|
||||
if (storageStats == null) {
|
||||
if (this.errno == ProtoCommon.ERR_NO_ENOENT) {
|
||||
notFoundCount++;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
} else if (storageStats.length == 0) {
|
||||
notFoundCount++;
|
||||
} else if (storageStats[0].getStatus() == ProtoCommon.FDFS_STORAGE_STATUS_ONLINE ||
|
||||
storageStats[0].getStatus() == ProtoCommon.FDFS_STORAGE_STATUS_ACTIVE) {
|
||||
this.errno = ProtoCommon.ERR_NO_EBUSY;
|
||||
return false;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
if (notFoundCount == trackerGroup.tracker_servers.length) {
|
||||
this.errno = ProtoCommon.ERR_NO_ENOENT;
|
||||
return false;
|
||||
}
|
||||
|
||||
notFoundCount = 0;
|
||||
for (serverIndex = 0; serverIndex < trackerGroup.tracker_servers.length; serverIndex++) {
|
||||
try {
|
||||
trackerServer = trackerGroup.getTrackerServer(serverIndex);
|
||||
} catch (IOException ex) {
|
||||
System.err.println("connect to server " + trackerGroup.tracker_servers[serverIndex].getAddress().getHostAddress() + ":" + trackerGroup.tracker_servers[serverIndex].getPort() + " fail");
|
||||
ex.printStackTrace(System.err);
|
||||
this.errno = ProtoCommon.ECONNREFUSED;
|
||||
return false;
|
||||
}
|
||||
if (!this.deleteStorage(trackerServer, groupName, storageIpAddr)) {
|
||||
if (this.errno != 0) {
|
||||
if (this.errno == ProtoCommon.ERR_NO_ENOENT) {
|
||||
notFoundCount++;
|
||||
} else if (this.errno != ProtoCommon.ERR_NO_EALREADY) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
if (notFoundCount == trackerGroup.tracker_servers.length) {
|
||||
this.errno = ProtoCommon.ERR_NO_ENOENT;
|
||||
return false;
|
||||
}
|
||||
|
||||
if (this.errno == ProtoCommon.ERR_NO_ENOENT) {
|
||||
this.errno = 0;
|
||||
}
|
||||
|
||||
return this.errno == 0;
|
||||
}
|
||||
}
|
||||
+101
@@ -0,0 +1,101 @@
|
||||
/**
|
||||
* Copyright (C) 2008 Happy Fish / YuQing
|
||||
* <p>
|
||||
* FastDFS Java Client may be copied only under the terms of the GNU Lesser
|
||||
* General Public License (LGPL).
|
||||
* Please visit the FastDFS Home Page https://github.com/happyfish100/fastdfs for more detail.
|
||||
*/
|
||||
|
||||
package com.csource.fastdfs;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.net.InetSocketAddress;
|
||||
|
||||
/**
|
||||
* Tracker server group
|
||||
*
|
||||
* @author Happy Fish / YuQing
|
||||
* @version Version 1.17
|
||||
*/
|
||||
public class TrackerGroup {
|
||||
public int tracker_server_index;
|
||||
public InetSocketAddress[] tracker_servers;
|
||||
protected Integer lock;
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
*
|
||||
* @param tracker_servers tracker servers
|
||||
*/
|
||||
public TrackerGroup(InetSocketAddress[] tracker_servers) {
|
||||
this.tracker_servers = tracker_servers;
|
||||
this.lock = new Integer(0);
|
||||
this.tracker_server_index = 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* return connected tracker server
|
||||
*
|
||||
* @return connected tracker server, null for fail
|
||||
*/
|
||||
public TrackerServer getTrackerServer(int serverIndex) throws IOException {
|
||||
return new TrackerServer(this.tracker_servers[serverIndex], serverIndex);
|
||||
}
|
||||
|
||||
/**
|
||||
* return connected tracker server
|
||||
*
|
||||
* @return connected tracker server, null for fail
|
||||
*/
|
||||
public TrackerServer getTrackerServer() throws IOException {
|
||||
int current_index;
|
||||
|
||||
synchronized (this.lock) {
|
||||
this.tracker_server_index++;
|
||||
if (this.tracker_server_index >= this.tracker_servers.length) {
|
||||
this.tracker_server_index = 0;
|
||||
}
|
||||
|
||||
current_index = this.tracker_server_index;
|
||||
}
|
||||
|
||||
try {
|
||||
return this.getTrackerServer(current_index);
|
||||
} catch (IOException ex) {
|
||||
System.err.println("connect to server " + this.tracker_servers[current_index].getAddress().getHostAddress() + ":" + this.tracker_servers[current_index].getPort() + " fail");
|
||||
ex.printStackTrace(System.err);
|
||||
}
|
||||
|
||||
for (int i = 0; i < this.tracker_servers.length; i++) {
|
||||
if (i == current_index) {
|
||||
continue;
|
||||
}
|
||||
|
||||
try {
|
||||
TrackerServer trackerServer = this.getTrackerServer(i);
|
||||
|
||||
synchronized (this.lock) {
|
||||
if (this.tracker_server_index == current_index) {
|
||||
this.tracker_server_index = i;
|
||||
}
|
||||
}
|
||||
|
||||
return trackerServer;
|
||||
} catch (IOException ex) {
|
||||
System.err.println("connect to server " + this.tracker_servers[i].getAddress().getHostAddress() + ":" + this.tracker_servers[i].getPort() + " fail");
|
||||
ex.printStackTrace(System.err);
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
public Object clone() {
|
||||
InetSocketAddress[] trackerServers = new InetSocketAddress[this.tracker_servers.length];
|
||||
for (int i = 0; i < trackerServers.length; i++) {
|
||||
trackerServers[i] = new InetSocketAddress(this.tracker_servers[i].getAddress().getHostAddress(), this.tracker_servers[i].getPort());
|
||||
}
|
||||
|
||||
return new TrackerGroup(trackerServers);
|
||||
}
|
||||
}
|
||||
+66
@@ -0,0 +1,66 @@
|
||||
/**
|
||||
* Copyright (C) 2008 Happy Fish / YuQing
|
||||
* <p>
|
||||
* FastDFS Java Client may be copied only under the terms of the GNU Lesser
|
||||
* General Public License (LGPL).
|
||||
* Please visit the FastDFS Home Page https://github.com/happyfish100/fastdfs for more detail.
|
||||
*/
|
||||
|
||||
package com.csource.fastdfs;
|
||||
|
||||
import com.csource.common.MyException;
|
||||
import com.csource.fastdfs.pool.ConnectionFactory;
|
||||
import com.csource.fastdfs.pool.ConnectionPool;
|
||||
import com.csource.fastdfs.pool.Connection;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.net.InetSocketAddress;
|
||||
|
||||
/**
|
||||
* Tracker Server Info
|
||||
*
|
||||
* @author Happy Fish / YuQing
|
||||
* @version Version 1.11
|
||||
*/
|
||||
public class TrackerServer {
|
||||
protected InetSocketAddress inetSockAddr;
|
||||
|
||||
protected int index;
|
||||
|
||||
|
||||
public TrackerServer(InetSocketAddress inetSockAddr) throws IOException {
|
||||
this.inetSockAddr = inetSockAddr;
|
||||
}
|
||||
|
||||
public TrackerServer(InetSocketAddress inetSockAddr, int index) {
|
||||
this.inetSockAddr = inetSockAddr;
|
||||
this.index = index;
|
||||
}
|
||||
|
||||
public Connection getConnection() throws MyException, IOException {
|
||||
Connection connection;
|
||||
if (ClientGlobal.g_connection_pool_enabled) {
|
||||
connection = ConnectionPool.getConnection(this.inetSockAddr);
|
||||
} else {
|
||||
connection = ConnectionFactory.create(this.inetSockAddr);
|
||||
}
|
||||
return connection;
|
||||
}
|
||||
|
||||
/**
|
||||
* get the server info
|
||||
*
|
||||
* @return the server info
|
||||
*/
|
||||
public InetSocketAddress getInetSocketAddress() {
|
||||
return this.inetSockAddr;
|
||||
}
|
||||
|
||||
public int getIndex() {
|
||||
return index;
|
||||
}
|
||||
|
||||
public void setIndex(int index) {
|
||||
this.index = index;
|
||||
}
|
||||
}
|
||||
+28
@@ -0,0 +1,28 @@
|
||||
/**
|
||||
* Copyright (C) 2008 Happy Fish / YuQing
|
||||
* <p>
|
||||
* FastDFS Java Client may be copied only under the terms of the GNU Lesser
|
||||
* General Public License (LGPL).
|
||||
* Please visit the FastDFS Home Page https://github.com/happyfish100/fastdfs for more detail.
|
||||
*/
|
||||
|
||||
package com.csource.fastdfs;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.OutputStream;
|
||||
|
||||
/**
|
||||
* upload file callback interface
|
||||
*
|
||||
* @author Happy Fish / YuQing
|
||||
* @version Version 1.0
|
||||
*/
|
||||
public interface UploadCallback {
|
||||
/**
|
||||
* send file content callback function, be called only once when the file uploaded
|
||||
*
|
||||
* @param out output stream for writing file content
|
||||
* @return 0 success, return none zero(errno) if fail
|
||||
*/
|
||||
int send(OutputStream out) throws IOException;
|
||||
}
|
||||
+56
@@ -0,0 +1,56 @@
|
||||
package com.csource.fastdfs;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.OutputStream;
|
||||
|
||||
/**
|
||||
* Upload file by stream
|
||||
*
|
||||
* @author zhouzezhong & Happy Fish / YuQing
|
||||
* @version Version 1.11
|
||||
*/
|
||||
public class UploadStream implements UploadCallback {
|
||||
private InputStream inputStream; //input stream for reading
|
||||
private long fileSize = 0; //size of the uploaded file
|
||||
|
||||
/**
|
||||
* constructor
|
||||
*
|
||||
* @param inputStream input stream for uploading
|
||||
* @param fileSize size of uploaded file
|
||||
*/
|
||||
public UploadStream(InputStream inputStream, long fileSize) {
|
||||
super();
|
||||
this.inputStream = inputStream;
|
||||
this.fileSize = fileSize;
|
||||
}
|
||||
|
||||
/**
|
||||
* send file content callback function, be called only once when the file uploaded
|
||||
*
|
||||
* @param out output stream for writing file content
|
||||
* @return 0 success, return none zero(errno) if fail
|
||||
*/
|
||||
@Override
|
||||
public int send(OutputStream out) throws IOException {
|
||||
long remainBytes = fileSize;
|
||||
byte[] buff = new byte[256 * 1024];
|
||||
int bytes;
|
||||
while (remainBytes > 0) {
|
||||
try {
|
||||
if ((bytes = inputStream.read(buff, 0, remainBytes > buff.length ? buff.length : (int) remainBytes)) < 0) {
|
||||
return -1;
|
||||
}
|
||||
} catch (IOException ex) {
|
||||
ex.printStackTrace();
|
||||
return -1;
|
||||
}
|
||||
|
||||
out.write(buff, 0, bytes);
|
||||
remainBytes -= bytes;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
+140
@@ -0,0 +1,140 @@
|
||||
package com.csource.fastdfs.pool;
|
||||
|
||||
|
||||
import com.csource.fastdfs.ProtoCommon;
|
||||
import com.csource.fastdfs.ClientGlobal;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.OutputStream;
|
||||
import java.net.InetSocketAddress;
|
||||
import java.net.Socket;
|
||||
|
||||
public class Connection {
|
||||
|
||||
private Socket sock;
|
||||
private InetSocketAddress inetSockAddr;
|
||||
private Long lastAccessTime = System.currentTimeMillis();
|
||||
|
||||
private boolean needActiveTest = false;
|
||||
|
||||
public Connection(Socket sock, InetSocketAddress inetSockAddr) {
|
||||
this.sock = sock;
|
||||
this.inetSockAddr = inetSockAddr;
|
||||
}
|
||||
|
||||
/**
|
||||
* get the server info
|
||||
*
|
||||
* @return the server info
|
||||
*/
|
||||
public InetSocketAddress getInetSocketAddress() {
|
||||
return this.inetSockAddr;
|
||||
}
|
||||
|
||||
public OutputStream getOutputStream() throws IOException {
|
||||
return this.sock.getOutputStream();
|
||||
}
|
||||
|
||||
public InputStream getInputStream() throws IOException {
|
||||
return this.sock.getInputStream();
|
||||
}
|
||||
|
||||
public Long getLastAccessTime() {
|
||||
return lastAccessTime;
|
||||
}
|
||||
|
||||
public void setLastAccessTime(Long lastAccessTime) {
|
||||
this.lastAccessTime = lastAccessTime;
|
||||
}
|
||||
|
||||
/**
|
||||
* @throws IOException
|
||||
*/
|
||||
public void close() throws IOException {
|
||||
//if connection enabled get from connection pool
|
||||
if (ClientGlobal.g_connection_pool_enabled) {
|
||||
ConnectionPool.closeConnection(this);
|
||||
} else {
|
||||
this.closeDirectly();
|
||||
}
|
||||
}
|
||||
|
||||
public void release() throws IOException {
|
||||
if (ClientGlobal.g_connection_pool_enabled) {
|
||||
ConnectionPool.releaseConnection(this);
|
||||
} else {
|
||||
this.closeDirectly();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* force close socket,
|
||||
*/
|
||||
public void closeDirectly() throws IOException {
|
||||
if (this.sock != null) {
|
||||
try {
|
||||
ProtoCommon.closeSocket(this.sock);
|
||||
} finally {
|
||||
this.sock = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public boolean activeTest() throws IOException {
|
||||
if (this.sock == null) {
|
||||
return false;
|
||||
}
|
||||
return ProtoCommon.activeTest(this.sock);
|
||||
}
|
||||
|
||||
public boolean isConnected() {
|
||||
boolean isConnected = false;
|
||||
if (sock != null) {
|
||||
if (sock.isConnected()) {
|
||||
isConnected = true;
|
||||
}
|
||||
}
|
||||
return isConnected;
|
||||
}
|
||||
|
||||
public boolean isAvaliable() {
|
||||
if (isConnected()) {
|
||||
if (sock.getPort() == 0) {
|
||||
return false;
|
||||
}
|
||||
if (sock.getInetAddress() == null) {
|
||||
return false;
|
||||
}
|
||||
if (sock.getRemoteSocketAddress() == null) {
|
||||
return false;
|
||||
}
|
||||
if (sock.isInputShutdown()) {
|
||||
return false;
|
||||
}
|
||||
if (sock.isOutputShutdown()) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public boolean isNeedActiveTest() {
|
||||
return needActiveTest;
|
||||
}
|
||||
|
||||
public void setNeedActiveTest(boolean needActiveTest) {
|
||||
this.needActiveTest = needActiveTest;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "Connection{" +
|
||||
"sock=" + sock +
|
||||
", inetSockAddr=" + inetSockAddr +
|
||||
", lastAccessTime=" + lastAccessTime +
|
||||
", needActiveTest=" + needActiveTest +
|
||||
'}';
|
||||
}
|
||||
}
|
||||
+29
@@ -0,0 +1,29 @@
|
||||
package com.csource.fastdfs.pool;
|
||||
|
||||
import com.csource.common.MyException;
|
||||
import com.csource.fastdfs.ClientGlobal;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.net.InetSocketAddress;
|
||||
import java.net.Socket;
|
||||
|
||||
public class ConnectionFactory {
|
||||
/**
|
||||
* create from InetSocketAddress
|
||||
*
|
||||
* @param socketAddress
|
||||
* @return
|
||||
* @throws IOException
|
||||
*/
|
||||
public static Connection create(InetSocketAddress socketAddress) throws MyException {
|
||||
try {
|
||||
Socket sock = new Socket();
|
||||
sock.setReuseAddress(true);
|
||||
sock.setSoTimeout(ClientGlobal.g_network_timeout);
|
||||
sock.connect(socketAddress, ClientGlobal.g_connect_timeout);
|
||||
return new Connection(sock, socketAddress);
|
||||
} catch (Exception e) {
|
||||
throw new MyException("connect to server " + socketAddress.getAddress().getHostAddress() + ":" + socketAddress.getPort() + " fail, emsg:" + e.getMessage());
|
||||
}
|
||||
}
|
||||
}
|
||||
+148
@@ -0,0 +1,148 @@
|
||||
package com.csource.fastdfs.pool;
|
||||
|
||||
import com.csource.common.MyException;
|
||||
import com.csource.fastdfs.ClientGlobal;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.net.InetSocketAddress;
|
||||
import java.util.LinkedList;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.concurrent.atomic.AtomicInteger;
|
||||
import java.util.concurrent.locks.Condition;
|
||||
import java.util.concurrent.locks.ReentrantLock;
|
||||
|
||||
public class ConnectionManager {
|
||||
|
||||
private InetSocketAddress inetSocketAddress;
|
||||
|
||||
/**
|
||||
* total create connection pool
|
||||
*/
|
||||
private AtomicInteger totalCount = new AtomicInteger();
|
||||
|
||||
/**
|
||||
* free connection count
|
||||
*/
|
||||
private AtomicInteger freeCount = new AtomicInteger();
|
||||
|
||||
/**
|
||||
* lock
|
||||
*/
|
||||
private ReentrantLock lock = new ReentrantLock(true);
|
||||
|
||||
private Condition condition = lock.newCondition();
|
||||
|
||||
/**
|
||||
* free connections
|
||||
*/
|
||||
private LinkedList<Connection> freeConnections = new LinkedList<Connection>();
|
||||
|
||||
private ConnectionManager() {
|
||||
|
||||
}
|
||||
|
||||
public ConnectionManager(InetSocketAddress socketAddress) {
|
||||
this.inetSocketAddress = socketAddress;
|
||||
}
|
||||
|
||||
public Connection getConnection() throws MyException {
|
||||
lock.lock();
|
||||
try {
|
||||
Connection connection = null;
|
||||
while (true) {
|
||||
if (freeCount.get() > 0) {
|
||||
freeCount.decrementAndGet();
|
||||
connection = freeConnections.poll();
|
||||
if (!connection.isAvaliable() || (System.currentTimeMillis() - connection.getLastAccessTime()) > ClientGlobal.g_connection_pool_max_idle_time) {
|
||||
closeConnection(connection);
|
||||
continue;
|
||||
}
|
||||
if (connection.isNeedActiveTest()) {
|
||||
boolean isActive = false;
|
||||
try {
|
||||
isActive = connection.activeTest();
|
||||
} catch (IOException e) {
|
||||
System.err.println("send to server[" + inetSocketAddress.getAddress().getHostAddress() + ":" + inetSocketAddress.getPort() + "] active test error ,emsg:" + e.getMessage());
|
||||
isActive = false;
|
||||
}
|
||||
if (!isActive) {
|
||||
closeConnection(connection);
|
||||
continue;
|
||||
} else {
|
||||
connection.setNeedActiveTest(false);
|
||||
}
|
||||
}
|
||||
} else if (ClientGlobal.g_connection_pool_max_count_per_entry == 0 || totalCount.get() < ClientGlobal.g_connection_pool_max_count_per_entry) {
|
||||
connection = ConnectionFactory.create(this.inetSocketAddress);
|
||||
totalCount.incrementAndGet();
|
||||
} else {
|
||||
try {
|
||||
if (condition.await(ClientGlobal.g_connection_pool_max_wait_time_in_ms, TimeUnit.MILLISECONDS)) {
|
||||
//wait single success
|
||||
continue;
|
||||
}
|
||||
throw new MyException("connect to server " + inetSocketAddress.getAddress().getHostAddress() + ":" + inetSocketAddress.getPort() + " fail, wait_time > " + ClientGlobal.g_connection_pool_max_wait_time_in_ms + "ms");
|
||||
} catch (InterruptedException e) {
|
||||
e.printStackTrace();
|
||||
throw new MyException("connect to server " + inetSocketAddress.getAddress().getHostAddress() + ":" + inetSocketAddress.getPort() + " fail, emsg:" + e.getMessage());
|
||||
}
|
||||
}
|
||||
return connection;
|
||||
}
|
||||
} finally {
|
||||
lock.unlock();
|
||||
}
|
||||
}
|
||||
|
||||
public void releaseConnection(Connection connection) {
|
||||
if (connection == null) {
|
||||
return;
|
||||
}
|
||||
lock.lock();
|
||||
try {
|
||||
connection.setLastAccessTime(System.currentTimeMillis());
|
||||
freeConnections.add(connection);
|
||||
freeCount.incrementAndGet();
|
||||
condition.signal();
|
||||
} finally {
|
||||
lock.unlock();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public void closeConnection(Connection connection) {
|
||||
try {
|
||||
if (connection != null) {
|
||||
totalCount.decrementAndGet();
|
||||
connection.closeDirectly();
|
||||
}
|
||||
} catch (IOException e) {
|
||||
System.err.println("close socket[" + inetSocketAddress.getAddress().getHostAddress() + ":" + inetSocketAddress.getPort() + "] error ,emsg:" + e.getMessage());
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
public void setActiveTestFlag() {
|
||||
if (freeCount.get() > 0) {
|
||||
lock.lock();
|
||||
try {
|
||||
for (Connection freeConnection : freeConnections) {
|
||||
freeConnection.setNeedActiveTest(true);
|
||||
}
|
||||
} finally {
|
||||
lock.unlock();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "ConnectionManager{" +
|
||||
"ip:port='" + inetSocketAddress.getAddress().getHostAddress() + ":" + inetSocketAddress.getPort() +
|
||||
", totalCount=" + totalCount +
|
||||
", freeCount=" + freeCount +
|
||||
", freeConnections =" + freeConnections +
|
||||
'}';
|
||||
}
|
||||
}
|
||||
+81
@@ -0,0 +1,81 @@
|
||||
package com.csource.fastdfs.pool;
|
||||
|
||||
import com.csource.common.MyException;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.net.InetSocketAddress;
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
|
||||
public class ConnectionPool {
|
||||
/**
|
||||
* key is ip:port, value is ConnectionManager
|
||||
*/
|
||||
private final static ConcurrentHashMap<String, ConnectionManager> CP = new ConcurrentHashMap<String, ConnectionManager>();
|
||||
|
||||
public static Connection getConnection(InetSocketAddress socketAddress) throws MyException {
|
||||
if (socketAddress == null) {
|
||||
return null;
|
||||
}
|
||||
String key = getKey(socketAddress);
|
||||
ConnectionManager connectionManager;
|
||||
connectionManager = CP.get(key);
|
||||
if (connectionManager == null) {
|
||||
synchronized (ConnectionPool.class) {
|
||||
connectionManager = CP.get(key);
|
||||
if (connectionManager == null) {
|
||||
connectionManager = new ConnectionManager(socketAddress);
|
||||
CP.put(key, connectionManager);
|
||||
}
|
||||
}
|
||||
}
|
||||
return connectionManager.getConnection();
|
||||
}
|
||||
|
||||
public static void releaseConnection(Connection connection) throws IOException {
|
||||
if (connection == null) {
|
||||
return;
|
||||
}
|
||||
String key = getKey(connection.getInetSocketAddress());
|
||||
ConnectionManager connectionManager = CP.get(key);
|
||||
if (connectionManager != null) {
|
||||
connectionManager.releaseConnection(connection);
|
||||
} else {
|
||||
connection.closeDirectly();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public static void closeConnection(Connection connection) throws IOException {
|
||||
if (connection == null) {
|
||||
return;
|
||||
}
|
||||
String key = getKey(connection.getInetSocketAddress());
|
||||
ConnectionManager connectionManager = CP.get(key);
|
||||
if (connectionManager != null) {
|
||||
connectionManager.closeConnection(connection);
|
||||
connectionManager.setActiveTestFlag();
|
||||
} else {
|
||||
connection.closeDirectly();
|
||||
}
|
||||
}
|
||||
|
||||
private static String getKey(InetSocketAddress socketAddress) {
|
||||
if (socketAddress == null) {
|
||||
return null;
|
||||
}
|
||||
return String.format("%s:%s", socketAddress.getAddress().getHostAddress(), socketAddress.getPort());
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
if (!CP.isEmpty()) {
|
||||
StringBuilder builder = new StringBuilder();
|
||||
for (Map.Entry<String, ConnectionManager> managerEntry : CP.entrySet()) {
|
||||
builder.append("key:[" + managerEntry.getKey() + " ]-------- entry:" + managerEntry.getValue() + "\n");
|
||||
}
|
||||
return builder.toString();
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user