I have a service to pass input array of object to server using protobuf and successfully receive it on the server. The problem is I got the response according to the response definition. Here is the response
[ { uuid: '',
quantity: 3,
procurement_detail_uuid: '',
distribution_officer_uuid: '',
substore_uuid: '2343423443423' },
{ uuid: '',
quantity: 3,
procurement_detail_uuid: '',
distribution_officer_uuid: '',
substore_uuid: '676767' } ]
and here is the definition of the input
message ProcurementStockDistributionUpsertReqInput {
string uuid = 1;
int32 quantity = 2;
string procurement_detail_uuid = 3;
string distribution_officer_uuid = 4;
string substore_uuid = 5;
}
as you can see some of the fields are empty. I thought about using oneof
If you have a message with many optional fields and where at most one
field will be set at the same time, you can enforce this behavior and
save memory by using the oneof feature.
I thought oneof is the right way to optionally pass fields which has value but hit the error. Then I rollback my code like this
service Procurement {
rpc distributeUpsert (ProcurementStockDistributionUpsertReq) returns (ProcurementStockDistributionRes) {}
}
message ProcurementStockDistributionUpsertReq {
message ProcurementStockDistributionUpsertReqInput {
string uuid = 1;
int32 quantity = 2;
string procurement_detail_uuid = 3;
string distribution_officer_uuid = 4;
string substore_uuid = 5;
}
repeated ProcurementStockDistributionUpsertReqInput stocks = 1;
}
How to pre-omit those empty fields in proto
Related
I'm currently working on implementing a gRPC nodejs client that should communicate with a java/kotlin gRPC server to test out the cross language codegen.
However when I try to make a call from my nodejs code I get a serialization failure and I have no idea why this is happening.
I've added as much as I can share, if you need any other code snippets, just ask.
I don't use any proto-loader, but rather have a buf-build setup that generates the code in typescript and Java.
The exact error being displayed is:
Error: 13 INTERNAL: Request message serialization failure: Expected argument of type com.example.resources.chat.v1.GetActiveChatSessionsRequest
If anyone could point me into the right direction or can help me out, would be greatly appreciated
Proto definition
syntax = "proto3";
package com.example.resources.chat.v1;
option java_package = "com.example.resources.chat.v1";
import "google/protobuf/timestamp.proto";
message ChatRoomOverviewItem {
string support_ticket_id = 1;
string chat_room_id = 2;
int32 number_of_unread_messages = 3;
google.protobuf.Timestamp last_message_received = 4;
repeated string participants = 5;
}
message GetActiveChatSessionsRequest {
string participant_id = 1;
int32 page = 2;
int32 limit = 3;
}
message GetActiveChatSessionsResponse {
bool last = 1;
int32 total_elements = 2;
int32 total_pages = 3;
int32 number_of_elements = 4;
bool first = 5;
int32 number = 6;
bool empty = 7;
repeated ChatRoomOverviewItem content = 8;
}
gRPC definition
syntax = "proto3";
package com.example.resources.chat.v1;
option java_package = "com.example.resources.chat.v1";
import "com/example/resources/chat/v1/chat.proto";
service ChatApiService {
rpc GetActiveChatSessions (GetActiveChatSessionsRequest) returns (GetActiveChatSessionsResponse);
}
NodeJS - Client
export const chatService = new ChatApiServiceClient(
process.env.CHAT_GRPC_URI || 'http://localhost:6565', ChannelCredentials.createInsecure())
---
chatApiService.getActiveChatSessions(new GetActiveChatSessionsRequest()
.setParticipantId(userId)
.setPage(req.params.page ? parseInt(req.params.page) : 0)
.setLimit(req.params.limit ? parseInt(req.params.init) : 25),
async (error, response) => {
if (error) throw error
else {
/* handle logic */
}
})
Kotlin - Server
#GRpcService
class ChatApiService(
private val streamObserverHandler: GrpcStreamObserverHandler,
private val chatRoomService: ChatRoomService,
private val chatMessageService: ChatMessageService
) : ChatApiServiceImplBase() {
override fun getActiveChatSessions(
request: Chat.GetActiveChatSessionsRequest,
responseObserver: StreamObserver<Chat.GetActiveChatSessionsResponse>
) {
streamObserverHandler.accept(
chatRoomService.getActiveChatRoomsForUser(
UUID.fromString(request.participantId),
PageRequest.of(request.page, request.limit)
),
responseObserver
)
}
i need a hint cause i don‘t know how to start.
I want to display a string char after char with a short delay but I’m not sure how to do it.
Should i convert the string into an array and display this array in a ForEach or is it possible to do this with string manipulation?
Thanks for every hint :-)
Michael
Here's an example where you can input a String. It will turn it into an array of Strings (for each character), add them onto the screen using an HStack and Text objects. Each Text has initial .opacity of 0.0 and then a function is called that will loop through each Text, turning the .opacity to 1.0.
struct CharView: View {
var characterArray: [String]
#State var characterLoopIndex: Int = -1
let loopDuration: Double = 0.5
init(input: String) {
characterArray = input.map { String($0) }
}
var body: some View {
HStack(spacing: 0) {
ForEach(characterArray.indices) { index in
Text("\(characterArray[index])")
.opacity(characterLoopIndex >= index ? 1 : 0)
.animation(.linear(duration: loopDuration))
}
}
.onAppear(perform: {
startCharacterAnimation()
})
}
func startCharacterAnimation() {
let timer = Timer.scheduledTimer(withTimeInterval: loopDuration, repeats: true) { (timer) in
characterLoopIndex += 1
if characterLoopIndex >= characterArray.count {
timer.invalidate()
}
}
timer.fire()
}
}
Usage:
CharView(input: "This is a test string")
Here is what I got:
I try to send requests to a service, that's what otherFunction() do. Each request use different parameters loaded from config.events. Then I want to append a randomParam to each event.
config = { events: [...] }
for(let i = 0; i < 100; i++){
config.events.forEach(element => {
// Get a random string
str = '&randomParam=' + Random.word(10)
element.url += str
console.log(element.url)
otherFunction(element)
// the element.url keep append random word 100 times, but I expect only one word append for each loop
})
}
I'd trid create a const var, using deep copy (JSON parse/stringify) and delete element.url and add it again. But none of it could solve my problem.
Actually, I did not know what exactly happend in my code and how this caused.
Current Result:
https://example.com/exampleApi/index.html?testParam=123&randomParam=rbveostvie
https://example.com/exampleApi/index.html?testParam=123&randomParam=rbveostvie&randomParam=bjanckrbjc
https://example.com/exampleApi/index.html?testParam=123&randomParam=rbveostvie&randomParam=bjanckrbjc&randomParam=rbuunvtdux
Expect Result:
https://example.com/exampleApi/index.html?testParam=123&randomParam=rbveostvie
https://example.com/exampleApi/index.html?testParam=123&randomParam=bjanckrbjc
https://example.com/exampleApi/index.html?testParam=123&randomParam=rbuunvtdux
You need to move the random string assignment out of the inner forEach loop.
var config = {
events: [
{
url: "foo"
},
{
url: "baz"
}
]
};
for (let i = 0; i < 100; i++) {
var str = "&randomParam=" + Random.word(10);
config.events.forEach(element => {
otherFunction(Object.assign({}, element, { url: element.url + str }));
});
}
For each i out of n=100 iterations, your inner forEach loop would iterate k=config.events.length times. By moving the random string outside the inner forEach loop, you would ensure that you generate n random strings instead of n * k random strings.
Edit
As per OP updated description, the actual problem is that element.url is being mutated. On every iteration, it will append the random string to the previously set url. Hence, I have updated my answer to include Object.assign({}, element, { url: element.url + str }) which will make sure no object in config.events gets mutated.
Please see below a working example:
function getRandomString() {
return Math.random()
.toString(36)
.substring(7);
}
var config = {
events: [{
url: "foo"
},
{
url: "baz"
}
]
};
function otherFunction(element) {
console.info(element.url);
}
for (let i = 0; i < 5; i++) {
var str = "&randomParam=" + getRandomString();
config.events.forEach(element => {
otherFunction(Object.assign({}, element, {
url: element.url + str
}));
});
}
I assume that config.events is an array of 100 elements, and you want to add a random string to every element.url.
You don't need two loops, one is enough. Remove that outer loop, and you'll get what you want
--EDIT--
According to the comment the author posted later, the outer loop should be moved to wrap the otherFunction call.
config = { events: [...] }
config.events.forEach(element => {
// Get a random string
str = '&randomParam=' + Random.word(10)
element.url += str
for(let i = 0; i < 100; i++){
otherFunction(element)
}
})
I'm serializing an object with YamlDotNet with both reference and value types. What i'm looking to accomplish is that my integer values of zero remain in the outputted yaml, but null values would be discarded. EmitDefaults looks to discard '0' for numeric values. i understand null is the default value for reference types. Json.Net solved this with breaking it out into the following properties:
NullValueHandling = NullValueHandling.Ignore,
DefaultValueHandling = DefaultValueHandling.Ignore,
is there any way to accomplish the below?
class foo
{
int index {get;set;}
string bar {get;set;}
}
new foo { index =0; bar = null }
would yield the following yaml:
index: 0
new foo { index =0; bar = "bar" }
would yield the following yaml:
index: 0
bar: bar
Thanks
Not sure this is what you want, but this is how I force all default values to be serialized:
public override string ToString()
{
var builder = new SerializerBuilder();
builder.EmitDefaults(); // Force even default values to be written, like 0, false.
var serializer = builder.Build();
var strWriter = new StringWriter();
serializer.Serialize(strWriter, this);
return strWriter.ToString();
}
I have an C struct (old library, blah blah blah) which contains an C string, now I need to convert CFString and Swift strings into this c string. Something like
struct Product{
char name[50];
char code[20];
}
So I'm trying to assign it as
productName.getCString(&myVarOfStructProduct.name, maxLength: 50, encoding: NSUTF8StringEncoding)
but the compiler is giving me the following error: cannot convert type (int8, int8, int8....) to [CChar].
A possible solution:
withUnsafeMutablePointer(&myVarOfStructProduct.name) {
strlcpy(UnsafeMutablePointer($0), productName, UInt(sizeofValue(myVarOfStructProduct.name)))
}
Inside the block, $0 is a (mutable) pointer to the tuple. This pointer is
converted to an UnsafeMutablePointer<Int8> as expected by the
BSD library function strlcpy().
It also uses the fact that the Swift string productName is automatically
to UnsafePointer<UInt8>
as explained in String value to UnsafePointer<UInt8> function parameter behavior. As mentioned in the comments in that
thread, this is done by creating a temporary UInt8 array (or sequence?).
So alternatively you could enumerate the UTF-8 bytes explicitly and put them
into the destination:
withUnsafeMutablePointer(&myVarOfStructProduct.name) {
tuplePtr -> Void in
var uint8Ptr = UnsafeMutablePointer<UInt8>(tuplePtr)
let size = sizeofValue(myVarOfStructProduct.name)
var idx = 0
if size == 0 { return } // C array has zero length.
for u in productName.utf8 {
if idx == size - 1 { break }
uint8Ptr[idx++] = u
}
uint8Ptr[idx] = 0 // NUL-terminate the C string in the array.
}
Yet another possible solution (with an intermediate NSData object):
withUnsafeMutablePointer(&myVarOfStructProduct.name) {
tuplePtr -> Void in
let tmp = productName + String(UnicodeScalar(0)) // Add NUL-termination
let data = tmp.dataUsingEncoding(NSUTF8StringEncoding, allowLossyConversion: true)!
data.getBytes(tuplePtr, length: sizeofValue(myVarOfStructProduct.name))
}
Update for Swift 3:
withUnsafeMutablePointer(to: &myVarOfStructProduct.name) {
$0.withMemoryRebound(to: Int8.self, capacity: MemoryLayout.size(ofValue: myVarOfStructProduct.name)) {
_ = strlcpy($0, productName, MemoryLayout.size(ofValue: myVarOfStructProduct.name))
}
}